Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

automatically generate a documentation of all configurables? #167

Open
patzm opened this issue Jun 29, 2022 · 1 comment
Open

automatically generate a documentation of all configurables? #167

patzm opened this issue Jun 29, 2022 · 1 comment

Comments

@patzm
Copy link

patzm commented Jun 29, 2022

Hi guys,

First of all, I really like your work! 馃憦. I have a question regarding documentation and transparency. If I have multiple places in my code that use @gin.configurable, can I somehow aggregate all those places and maybe even generate (Sphinx) documentation out of it?

Example:

@gin.configurable
def fun_a(param_a: str, param_b: bool = False, param_c: Sequence[int] = (1, 2, 3)):
    """some docstring that even describes the parameters"""
    pass

@gin.configurable
def fun_b(param_a: float = 1.0):
    pass

Can I get output like

Configurables:

fun_a
    param_a: string
        I am parameter A.
    param_b: bool, default `False`
        I am parameter B.
    param_c: Sequence of integers, default `(1, 2, 3)`
        I am parameter A.

fun_b
    param_a: float, default 1.0
        I am parameter A.

maybe even in machine readable format that anything could read and further process.

@fgerzer
Copy link

fgerzer commented Jul 4, 2022

As a step on the way to this, these are the functions I currently use to get all gin parameters:

def get_all_gin_configurable_signatures() -> dict[str, inspect.Signature]:
    """Get the signatures for all things that are gin-configurable before gin has been applied.

    Returns
    -------
    A dictionary mapping, for each configurable, name (including full module path) to a dictionary mapping parameter
    name to default value. Example: If we only have the L1Loss configurable, we can expect

    .. code-block:: python

        {"torch.nn.L1Loss": {"size_average": None, "reduce": None, "reduction": "mean"}}

    as a result. Parameters might be :class:`inspect.Parameter.empty`.
    """
    gin_configurables = {}
    for name, selectable in gin.config._REGISTRY._selector_map.items():
        gin_configurables[name] = inspect.signature(selectable.wrapped)
    return gin_configurables


def get_all_gin_parameters() -> dict[tuple[str, str], Any]:
    """Get parameters for all things that are gin-configurable after gin-settings have been applied.

    Returns
    -------
    A dictionary mapping, for each configurable, name (including full module path) to a dictionary mapping parameter
    name to default value. If multiple scopes are defined, we return multiple entries. This includes configurables that
    have not been set by gin.

    Example: If we have the L1Loss configurable and have it defined with different parameters in the scope
    `surface_head`, we can expect

    .. code-block:: python

    {
        ("", "torch.nn.L1Loss"):              {"size_average": None, "reduce": None, "reduction": "mean"},
        ("surface_head", "torch.nn.L1Loss"):  {"size_average": None, "reduce": None, "reduction": "sum"}
    }

    as a result. Parameters might be :class:`inspect.Parameter.empty`.

    Does not currently resolve macros or class definitions.
    """
    gin_signatures = get_all_gin_configurable_signatures()
    gin_configurables: dict[tuple[str, str], Any] = {}
    empty_scope = ""
    for name, signature in gin_signatures.items():
        # Add the default parameters with an empty scope.
        gin_configurables[(empty_scope, name)] = {k: v.default for k, v in signature.parameters.items()}
    for (scope, name), param_dict in get_gin_set_params().items():
        gin_configurables[(scope, name)] = copy.deepcopy(gin_configurables[(empty_scope, name)])
        for param_name, new_val in param_dict.items():
            gin_configurables[(scope, name)][param_name] = new_val
    return gin_configurables


def get_gin_set_params() -> dict[tuple[str, str], Any]:
    """Get parameters for all things that gin is modifying.

    Returns
    -------
    A dictionary mapping, for each configurable, a tuple of (scope, name) mapped to the parameter it is set to.
    scope is an empty string if this applies to everything.
    """
    return gin.config._CONFIG

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants