Repository: google/benchmark
File: bindings/python/google_benchmark/__init__.py (Python)

Code before:
    kMillisecond as kMillisecond,
    kNanosecond as kNanosecond,
    kSecond as kSecond,
    o1 as o1,
    oAuto as oAuto,
    oLambda as oLambda,
    oLogN as oLogN,
    oN as oN,
    oNCubed as oNCubed,
    oNLogN as oNLogN,
    oNone as oNone,
    oNSquared as oNSquared,
)

__version__ = "1.9.4"


HAS_ABSL = False
with contextlib.suppress(ImportError):
    # check if absl-py is available.
    import absl

    HAS_ABSL = True
    del absl

del contextlib


class __OptionMaker:
    """A stateless class to collect benchmark options.

    Collect all decorator calls like @option.range(start=0, limit=1<<5).
    """

    class Options:
        """Pure data class to store options calls, along with the benchmarked
        function."""

        def __init__(self, func):
            self.func = func
            self.builder_calls = []

    @classmethod
    def make(cls, func_or_options):
        """Make Options from Options or the benchmarked function."""
        if isinstance(func_or_options, cls.Options):
            return func_or_options
        return cls.Options(func_or_options)

    def __getattr__(self, builder_name):
        """Append option call in the Options."""

Review comment (performance):
Not sure about this bit yet - 1), it still requires a `from absl import app` statement in all APIs below (it will be cached in `sys.modules` in all but the first call, but still), and 2) it could break users importing `contextlib` before `google-benchmark`, as this call marks _all_ previously loaded contextlib modules for GC.

Code after:
    kNanosecond as kNanosecond,
    kSecond as kSecond,
    o1 as o1,
    oAuto as oAuto,
    oLambda as oLambda,
    oLogN as oLogN,
    oN as oN,
    oNCubed as oNCubed,
    oNLogN as oNLogN,
    oNone as oNone,
    oNSquared as oNSquared,
)

__version__ = "1.9.4"


class __OptionMaker:
    """A stateless class to collect benchmark options.

    Collect all decorator calls like @option.range(start=0, limit=1<<5).
    """

    class Options:
        """Pure data class to store options calls, along with the benchmarked
        function."""

        def __init__(self, func):
            self.func = func
            self.builder_calls = []

    @classmethod
    def make(cls, func_or_options):
        """Make Options from Options or the benchmarked function."""
        if isinstance(func_or_options, cls.Options):
            return func_or_options
        return cls.Options(func_or_options)

    def __getattr__(self, builder_name):
        """Append option call in the Options."""

        # The function that get returned on @option.range(start=0, limit=1<<5).
        def __builder_method(*args, **kwargs):
            # The decorator that get called, either with the benchmared function
            # or the previous Options
            def __decorator(func_or_options):
                options = self.make(func_or_options)
                options.builder_calls.append((builder_name, args, kwargs))
                # The decorator returns Options so it is not technically a
                # decorator and needs a final call to @register
                return options