Skip to content

Commit

Permalink
Avoid the expensive inspect calls when the results will be the same f…
Browse files Browse the repository at this point in the history
…or every object.
  • Loading branch information
tonyandrewmeyer committed Dec 13, 2024
1 parent 9086779 commit 14532aa
Showing 1 changed file with 29 additions and 11 deletions.
40 changes: 29 additions & 11 deletions testing/src/scenario/state.py
Original file line number Diff line number Diff line change
Expand Up @@ -122,26 +122,40 @@ class _MaxPositionalArgs:

_max_positional_args = n

def __new__(cls, *args: Any, **kwargs: Any):
@classmethod
def _annotate_class(cls):
"""Record information about which parameters are positional vs. keyword-only."""
if hasattr(cls, "_init_parameters"):
# We don't support dynamically changing the signature of a
# class, so we assume here it's the same as previously.
return
# inspect.signature guarantees the order of parameters is as
# declared, which aligns with dataclasses. Simpler ways of
# getting the arguments (like __annotations__) do not have that
# guarantee, although in practice it is the case.
parameters = inspect.signature(cls.__init__).parameters
required_args = [
cls._init_parameters = parameters = inspect.signature(
cls.__init__
).parameters
cls._init_kw_only = {
name
for name in tuple(parameters)[cls._max_positional_args :]
if not name.startswith("_")
}
cls._init_required_args = [
name
for name in tuple(parameters)
if parameters[name].default is inspect.Parameter.empty
and name not in kwargs
and name != "self"
if name != "self"
and parameters[name].default is inspect.Parameter.empty
]

def __new__(cls, *args: Any, **kwargs: Any):
cls._annotate_class()
required_args = [
name for name in cls._init_required_args if name not in kwargs
]
n_posargs = len(args)
max_n_posargs = cls._max_positional_args
kw_only = {
name
for name in tuple(parameters)[max_n_posargs:]
if not name.startswith("_")
}
kw_only = cls._init_kw_only
if n_posargs > max_n_posargs:
raise TypeError(
f"{cls.__name__} takes {max_n_posargs} positional "
Expand Down Expand Up @@ -180,6 +194,10 @@ def __reduce__(self):
return _MaxPositionalArgs


# A lot of JujuLogLine objects are created, so we want them to be fast and light.
# Dataclasses define __slots__, so are small, and a namedtuple is actually
# slower to create than a dataclass. A plain dictionary (or TypedDict) would be
# about twice as fast, but less convenient to use.
@dataclasses.dataclass(frozen=True)
class JujuLogLine:
"""An entry in the Juju debug-log."""
Expand Down

0 comments on commit 14532aa

Please sign in to comment.