Skip to content

Commit

Permalink
Switch from attr to attrs namespace.
Browse files Browse the repository at this point in the history
  • Loading branch information
domdfcoding committed Aug 21, 2024
1 parent 0a21f45 commit a584b92
Show file tree
Hide file tree
Showing 20 changed files with 385 additions and 356 deletions.
20 changes: 10 additions & 10 deletions .github/workflows/python_ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,16 +28,16 @@ jobs:
fail-fast: False
matrix:
config:
- {python-version: "3.7", testenvs: "py37-attrs{21.2,21.4,22.2,23.1,23.2,latest},py37-mypy{0.900,0.910,0.921,0.931,1.0.1,1.2.0,1.4.1},py37-sphinx{4,5},build", experimental: False}
- {python-version: "3.8", testenvs: "py38-attrs{21.2,21.4,22.2,23.1,23.2,latest},py38-mypy{0.900,0.910,0.921,0.931,1.0.1,1.2.0,1.4.1,1.6.1,latest},py38-sphinx{4,5,6,7},build", experimental: False}
- {python-version: "3.9", testenvs: "py39-attrs{21.2,21.4,22.2,23.1,23.2,latest},py39-mypy{0.900,0.910,0.921,0.931,1.0.1,1.2.0,1.4.1,1.6.1,latest},py39-sphinx{4,5,6,7},build", experimental: False}
- {python-version: "3.10", testenvs: "py310-attrs{21.2,21.4,22.2,23.1,23.2,latest},py310-mypy{0.900,0.910,0.921,0.931,1.0.1,1.2.0,1.4.1,1.6.1,latest},py310-sphinx{4,5,6,7},build", experimental: False}
- {python-version: "3.11", testenvs: "py311-attrs{21.2,21.4,22.2,23.1,23.2,latest},py311-mypy{0.900,0.910,0.921,0.931,1.0.1,1.2.0,1.4.1,1.6.1,latest},py311-sphinx{4,5,6,7},build", experimental: False}
- {python-version: "3.12", testenvs: "py312-attrs{21.2,21.4,22.2,23.1,23.2,latest},py312-mypy{1.0.1,1.2.0,1.4.1,1.6.1,latest},py312-sphinx{4,5,6,7},build", experimental: True}
- {python-version: "3.13.0-beta.4", testenvs: "py313-dev-attrs{21.2,21.4,22.2,23.1,23.2,latest},py313-dev-mypy{1.0.1,1.2.0,1.4.1,1.6.1,latest},py313-dev-sphinx{6,7},build", experimental: True}
- {python-version: "pypy-3.7", testenvs: "pypy37-attrs{21.2,21.4,22.2,23.1,23.2,latest},pypy37-sphinx{4,5},build", experimental: False}
- {python-version: "pypy-3.8", testenvs: "pypy38-attrs{21.2,21.4,22.2,23.1,23.2,latest},pypy38-sphinx{4,5,6,7},build", experimental: False}
- {python-version: "pypy-3.9-v7.3.15", testenvs: "pypy39-attrs{21.2,21.4,22.2,23.1,23.2,latest},pypy39-sphinx{4,5,6,7},build", experimental: True}
- {python-version: "3.7", testenvs: "py37-attrs{21.3,21.4,22.2,23.1,23.2,latest},py37-mypy{0.900,0.910,0.921,0.931,1.0.1,1.2.0,1.4.1},py37-sphinx{4,5},build", experimental: False}
- {python-version: "3.8", testenvs: "py38-attrs{21.3,21.4,22.2,23.1,23.2,latest},py38-mypy{0.900,0.910,0.921,0.931,1.0.1,1.2.0,1.4.1,1.6.1,latest},py38-sphinx{4,5,6,7},build", experimental: False}
- {python-version: "3.9", testenvs: "py39-attrs{21.3,21.4,22.2,23.1,23.2,latest},py39-mypy{0.900,0.910,0.921,0.931,1.0.1,1.2.0,1.4.1,1.6.1,latest},py39-sphinx{4,5,6,7},build", experimental: False}
- {python-version: "3.10", testenvs: "py310-attrs{21.3,21.4,22.2,23.1,23.2,latest},py310-mypy{0.900,0.910,0.921,0.931,1.0.1,1.2.0,1.4.1,1.6.1,latest},py310-sphinx{4,5,6,7},build", experimental: False}
- {python-version: "3.11", testenvs: "py311-attrs{21.3,21.4,22.2,23.1,23.2,latest},py311-mypy{0.900,0.910,0.921,0.931,1.0.1,1.2.0,1.4.1,1.6.1,latest},py311-sphinx{4,5,6,7},build", experimental: False}
- {python-version: "3.12", testenvs: "py312-attrs{21.3,21.4,22.2,23.1,23.2,latest},py312-mypy{1.0.1,1.2.0,1.4.1,1.6.1,latest},py312-sphinx{4,5,6,7},build", experimental: True}
- {python-version: "3.13.0-beta.4", testenvs: "py313-dev-attrs{21.3,21.4,22.2,23.1,23.2,latest},py313-dev-mypy{1.0.1,1.2.0,1.4.1,1.6.1,latest},py313-dev-sphinx{6,7},build", experimental: True}
- {python-version: "pypy-3.7", testenvs: "pypy37-attrs{21.3,21.4,22.2,23.1,23.2,latest},pypy37-sphinx{4,5},build", experimental: False}
- {python-version: "pypy-3.8", testenvs: "pypy38-attrs{21.3,21.4,22.2,23.1,23.2,latest},pypy38-sphinx{4,5,6,7},build", experimental: False}
- {python-version: "pypy-3.9-v7.3.15", testenvs: "pypy39-attrs{21.3,21.4,22.2,23.1,23.2,latest},pypy39-sphinx{4,5,6,7},build", experimental: True}

steps:
- name: Checkout 🛎️
Expand Down
20 changes: 10 additions & 10 deletions .github/workflows/python_ci_linux.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,16 +29,16 @@ jobs:
fail-fast: False
matrix:
config:
- {python-version: "3.7", testenvs: "py37-attrs{21.2,21.4,22.2,23.1,23.2,latest},py37-mypy{0.900,0.910,0.921,0.931,1.0.1,1.2.0,1.4.1},py37-sphinx{4,5},build", experimental: False}
- {python-version: "3.8", testenvs: "py38-attrs{21.2,21.4,22.2,23.1,23.2,latest},py38-mypy{0.900,0.910,0.921,0.931,1.0.1,1.2.0,1.4.1,1.6.1,latest},py38-sphinx{4,5,6,7},build", experimental: False}
- {python-version: "3.9", testenvs: "py39-attrs{21.2,21.4,22.2,23.1,23.2,latest},py39-mypy{0.900,0.910,0.921,0.931,1.0.1,1.2.0,1.4.1,1.6.1,latest},py39-sphinx{4,5,6,7},build", experimental: False}
- {python-version: "3.10", testenvs: "py310-attrs{21.2,21.4,22.2,23.1,23.2,latest},py310-mypy{0.900,0.910,0.921,0.931,1.0.1,1.2.0,1.4.1,1.6.1,latest},py310-sphinx{4,5,6,7},build", experimental: False}
- {python-version: "3.11", testenvs: "py311-attrs{21.2,21.4,22.2,23.1,23.2,latest},py311-mypy{0.900,0.910,0.921,0.931,1.0.1,1.2.0,1.4.1,1.6.1,latest},py311-sphinx{4,5,6,7},build", experimental: False}
- {python-version: "3.12", testenvs: "py312-attrs{21.2,21.4,22.2,23.1,23.2,latest},py312-mypy{1.0.1,1.2.0,1.4.1,1.6.1,latest},py312-sphinx{4,5,6,7},build", experimental: True}
- {python-version: "3.13.0-beta.4", testenvs: "py313-dev-attrs{21.2,21.4,22.2,23.1,23.2,latest},py313-dev-mypy{1.0.1,1.2.0,1.4.1,1.6.1,latest},py313-dev-sphinx{6,7},build", experimental: True}
- {python-version: "pypy-3.7", testenvs: "pypy37-attrs{21.2,21.4,22.2,23.1,23.2,latest},pypy37-sphinx{4,5},build", experimental: False}
- {python-version: "pypy-3.8", testenvs: "pypy38-attrs{21.2,21.4,22.2,23.1,23.2,latest},pypy38-sphinx{4,5,6,7},build", experimental: False}
- {python-version: "pypy-3.9", testenvs: "pypy39-attrs{21.2,21.4,22.2,23.1,23.2,latest},pypy39-sphinx{4,5,6,7},build", experimental: True}
- {python-version: "3.7", testenvs: "py37-attrs{21.3,21.4,22.2,23.1,23.2,latest},py37-mypy{0.900,0.910,0.921,0.931,1.0.1,1.2.0,1.4.1},py37-sphinx{4,5},build", experimental: False}
- {python-version: "3.8", testenvs: "py38-attrs{21.3,21.4,22.2,23.1,23.2,latest},py38-mypy{0.900,0.910,0.921,0.931,1.0.1,1.2.0,1.4.1,1.6.1,latest},py38-sphinx{4,5,6,7},build", experimental: False}
- {python-version: "3.9", testenvs: "py39-attrs{21.3,21.4,22.2,23.1,23.2,latest},py39-mypy{0.900,0.910,0.921,0.931,1.0.1,1.2.0,1.4.1,1.6.1,latest},py39-sphinx{4,5,6,7},build", experimental: False}
- {python-version: "3.10", testenvs: "py310-attrs{21.3,21.4,22.2,23.1,23.2,latest},py310-mypy{0.900,0.910,0.921,0.931,1.0.1,1.2.0,1.4.1,1.6.1,latest},py310-sphinx{4,5,6,7},build", experimental: False}
- {python-version: "3.11", testenvs: "py311-attrs{21.3,21.4,22.2,23.1,23.2,latest},py311-mypy{0.900,0.910,0.921,0.931,1.0.1,1.2.0,1.4.1,1.6.1,latest},py311-sphinx{4,5,6,7},build", experimental: False}
- {python-version: "3.12", testenvs: "py312-attrs{21.3,21.4,22.2,23.1,23.2,latest},py312-mypy{1.0.1,1.2.0,1.4.1,1.6.1,latest},py312-sphinx{4,5,6,7},build", experimental: True}
- {python-version: "3.13.0-beta.4", testenvs: "py313-dev-attrs{21.3,21.4,22.2,23.1,23.2,latest},py313-dev-mypy{1.0.1,1.2.0,1.4.1,1.6.1,latest},py313-dev-sphinx{6,7},build", experimental: True}
- {python-version: "pypy-3.7", testenvs: "pypy37-attrs{21.3,21.4,22.2,23.1,23.2,latest},pypy37-sphinx{4,5},build", experimental: False}
- {python-version: "pypy-3.8", testenvs: "pypy38-attrs{21.3,21.4,22.2,23.1,23.2,latest},pypy38-sphinx{4,5,6,7},build", experimental: False}
- {python-version: "pypy-3.9", testenvs: "pypy39-attrs{21.3,21.4,22.2,23.1,23.2,latest},pypy39-sphinx{4,5,6,7},build", experimental: True}

steps:
- name: Checkout 🛎️
Expand Down
20 changes: 10 additions & 10 deletions .github/workflows/python_ci_macos.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,16 +28,16 @@ jobs:
fail-fast: False
matrix:
config:
- {python-version: "3.7", testenvs: "py37-attrs{21.2,21.4,22.2,23.1,23.2,latest},py37-mypy{0.900,0.910,0.921,0.931,1.0.1,1.2.0,1.4.1},py37-sphinx{4,5},build", experimental: False}
- {python-version: "3.8", testenvs: "py38-attrs{21.2,21.4,22.2,23.1,23.2,latest},py38-mypy{0.900,0.910,0.921,0.931,1.0.1,1.2.0,1.4.1,1.6.1,latest},py38-sphinx{4,5,6,7},build", experimental: False}
- {python-version: "3.9", testenvs: "py39-attrs{21.2,21.4,22.2,23.1,23.2,latest},py39-mypy{0.900,0.910,0.921,0.931,1.0.1,1.2.0,1.4.1,1.6.1,latest},py39-sphinx{4,5,6,7},build", experimental: False}
- {python-version: "3.10", testenvs: "py310-attrs{21.2,21.4,22.2,23.1,23.2,latest},py310-mypy{0.900,0.910,0.921,0.931,1.0.1,1.2.0,1.4.1,1.6.1,latest},py310-sphinx{4,5,6,7},build", experimental: False}
- {python-version: "3.11", testenvs: "py311-attrs{21.2,21.4,22.2,23.1,23.2,latest},py311-mypy{0.900,0.910,0.921,0.931,1.0.1,1.2.0,1.4.1,1.6.1,latest},py311-sphinx{4,5,6,7},build", experimental: False}
- {python-version: "3.12", testenvs: "py312-attrs{21.2,21.4,22.2,23.1,23.2,latest},py312-mypy{1.0.1,1.2.0,1.4.1,1.6.1,latest},py312-sphinx{4,5,6,7},build", experimental: True}
- {python-version: "3.13.0-beta.4", testenvs: "py313-dev-attrs{21.2,21.4,22.2,23.1,23.2,latest},py313-dev-mypy{1.0.1,1.2.0,1.4.1,1.6.1,latest},py313-dev-sphinx{6,7},build", experimental: True}
- {python-version: "pypy-3.7", testenvs: "pypy37-attrs{21.2,21.4,22.2,23.1,23.2,latest},pypy37-sphinx{4,5},build", experimental: False}
- {python-version: "pypy-3.8", testenvs: "pypy38-attrs{21.2,21.4,22.2,23.1,23.2,latest},pypy38-sphinx{4,5,6,7},build", experimental: False}
- {python-version: "pypy-3.9", testenvs: "pypy39-attrs{21.2,21.4,22.2,23.1,23.2,latest},pypy39-sphinx{4,5,6,7},build", experimental: True}
- {python-version: "3.7", testenvs: "py37-attrs{21.3,21.4,22.2,23.1,23.2,latest},py37-mypy{0.900,0.910,0.921,0.931,1.0.1,1.2.0,1.4.1},py37-sphinx{4,5},build", experimental: False}
- {python-version: "3.8", testenvs: "py38-attrs{21.3,21.4,22.2,23.1,23.2,latest},py38-mypy{0.900,0.910,0.921,0.931,1.0.1,1.2.0,1.4.1,1.6.1,latest},py38-sphinx{4,5,6,7},build", experimental: False}
- {python-version: "3.9", testenvs: "py39-attrs{21.3,21.4,22.2,23.1,23.2,latest},py39-mypy{0.900,0.910,0.921,0.931,1.0.1,1.2.0,1.4.1,1.6.1,latest},py39-sphinx{4,5,6,7},build", experimental: False}
- {python-version: "3.10", testenvs: "py310-attrs{21.3,21.4,22.2,23.1,23.2,latest},py310-mypy{0.900,0.910,0.921,0.931,1.0.1,1.2.0,1.4.1,1.6.1,latest},py310-sphinx{4,5,6,7},build", experimental: False}
- {python-version: "3.11", testenvs: "py311-attrs{21.3,21.4,22.2,23.1,23.2,latest},py311-mypy{0.900,0.910,0.921,0.931,1.0.1,1.2.0,1.4.1,1.6.1,latest},py311-sphinx{4,5,6,7},build", experimental: False}
- {python-version: "3.12", testenvs: "py312-attrs{21.3,21.4,22.2,23.1,23.2,latest},py312-mypy{1.0.1,1.2.0,1.4.1,1.6.1,latest},py312-sphinx{4,5,6,7},build", experimental: True}
- {python-version: "3.13.0-beta.4", testenvs: "py313-dev-attrs{21.3,21.4,22.2,23.1,23.2,latest},py313-dev-mypy{1.0.1,1.2.0,1.4.1,1.6.1,latest},py313-dev-sphinx{6,7},build", experimental: True}
- {python-version: "pypy-3.7", testenvs: "pypy37-attrs{21.3,21.4,22.2,23.1,23.2,latest},pypy37-sphinx{4,5},build", experimental: False}
- {python-version: "pypy-3.8", testenvs: "pypy38-attrs{21.3,21.4,22.2,23.1,23.2,latest},pypy38-sphinx{4,5,6,7},build", experimental: False}
- {python-version: "pypy-3.9", testenvs: "pypy39-attrs{21.3,21.4,22.2,23.1,23.2,latest},pypy39-sphinx{4,5,6,7},build", experimental: True}

steps:
- name: Checkout 🛎️
Expand Down
40 changes: 20 additions & 20 deletions attr_utils/annotations.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
The annotation can also be provided via the ``'annotation'`` key in the
`metadata dict <https://www.attrs.org/en/stable/examples.html#metadata>`_.
If you prefer you can instead provide this as a keyword argument to :func:`~.attrib`
which will construct the metadata dict and call :func:`attr.ib` for you.
which will construct the metadata dict and call :func:`attrs.field` for you.
.. _attrs: https://www.attrs.org/en/stable/
Expand Down Expand Up @@ -52,12 +52,12 @@ def untyped_converter(arg):
return arg
@attr.s
@attrs.define
class SomeClass:
a_string: str = attr.ib(converter=str)
custom_converter: Any = attr.ib(converter=my_converter)
untyped: Tuple[str, int, float] = attr.ib(converter=untyped_converter)
annotated: List[str] = attr.ib(
a_string: str = attrs.field(converter=str)
custom_converter: Any = attrs.field(converter=my_converter)
untyped: Tuple[str, int, float] = attrs.field(converter=untyped_converter)
annotated: List[str] = attrs.field(
converter=list,
metadata={"annotation": Sequence[str]},
)
Expand Down Expand Up @@ -123,7 +123,7 @@ class SomeClass:
from typing import TYPE_CHECKING, Any, Callable, Dict, Iterable, List, Optional, Type, TypeVar, Union, cast

# 3rd party
import attr
import attrs

# this package
import attr_utils
Expand Down Expand Up @@ -153,17 +153,17 @@ def add_init_annotations(obj: _C) -> _C:
.. _attrs: https://www.attrs.org/en/stable/
"""

if not attr.has(obj): # type: ignore
if not attrs.has(obj): # type: ignore
return obj

if hasattr(obj, "__attrs_init__"):
return obj # type: ignore[return-value]

annotations: Dict[str, Optional[Type]] = {"return": None}

attrs = attr.fields(obj)
fields = attrs.fields(obj)

for a in attrs:
for a in fields:
arg_name = a.name.lstrip('_')

if a.init is True and a.type is not None:
Expand Down Expand Up @@ -197,13 +197,13 @@ def add_init_annotations(obj: _C) -> _C:


def attrib(
default=attr.NOTHING,
default=attrs.NOTHING,
validator=None,
repr: bool = True, # noqa: A002 # pylint: disable=redefined-builtin
hash=None, # noqa: A002 # pylint: disable=redefined-builtin
init=True,
metadata=None,
annotation: Union[Type, object] = attr.NOTHING,
annotation: Union[Type, object] = attrs.NOTHING,
converter=None,
factory=None,
kw_only: bool = False,
Expand All @@ -212,7 +212,7 @@ def attrib(
**kwargs,
):
r"""
Wrapper around :func:`attr.ib` which supports the ``annotation``
Wrapper around :func:`attrs.field` which supports the ``annotation``
keyword argument for use by :func:`~.add_init_annotations`.
.. versionadded:: 0.2.0
Expand All @@ -231,16 +231,16 @@ def attrib(
:param eq:
:param order:
See the documentation for :func:`attr.ib` for descriptions of the other arguments.
See the documentation for :func:`attrs.field` for descriptions of the other arguments.
""" # noqa: D400

if annotation is not attr.NOTHING:
if annotation is not attrs.NOTHING:
if metadata is None:
metadata = {}

metadata["annotation"] = annotation

return attr.ib(
return attrs.field(
default=default,
validator=validator,
repr=repr,
Expand Down Expand Up @@ -309,7 +309,7 @@ def parse_occupations(occupations: Iterable[str]) -> Iterable[str]: # pragma: n
return [str(x) for x in occupations]


@attr.s
@attrs.define
class AttrsClass:
"""
Example of using :func:`~.add_init_annotations` for attrs_ classes with Sphinx documentation.
Expand All @@ -321,6 +321,6 @@ class AttrsClass:
:param occupations: The occupation(s) of the person.
"""

name: str = attr.ib(converter=str)
age: int = attr.ib(converter=int)
occupations: List[str] = attr.ib(converter=parse_occupations)
name: str = attrs.field(converter=str)
age: int = attrs.field(converter=int)
occupations: List[str] = attrs.field(converter=parse_occupations)
10 changes: 5 additions & 5 deletions attr_utils/autoattrs.py
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@
from typing import TYPE_CHECKING, Any, Dict, List, MutableMapping, Optional, Tuple, Type

# 3rd party
import attr
import attrs
from sphinx.application import Sphinx # nodep
from sphinx.ext.autodoc import ClassDocumenter, Documenter # nodep
from sphinx.pycode import ModuleAnalyzer # nodep
Expand Down Expand Up @@ -181,7 +181,7 @@ def can_document_member(cls, member: Any, membername: str, isattr: bool, parent:
.. latex:clearpage::
"""

return attr.has(member) and isinstance(member, type)
return attrs.has(member) and isinstance(member, type)

def add_content(self, more_content: Any, no_docstring: bool = False) -> None: # type: ignore
"""
Expand Down Expand Up @@ -244,7 +244,7 @@ def import_object(self, raiseerror: bool = False) -> bool:

ret = super().import_object(raiseerror)

if attr.has(self.object):
if attrs.has(self.object):
self.object = add_attrs_doc(self.object)

return ret
Expand Down Expand Up @@ -281,7 +281,7 @@ def sort_members(
params, pre_output, post_output = self._get_docstring()
all_docs = {}

for field in (a.name for a in attr.fields(self.object) if a.init):
for field in (a.name for a in attrs.fields(self.object) if a.init):
doc: List[str] = ['']

# Prefer doc from class docstring
Expand Down Expand Up @@ -344,7 +344,7 @@ def filter_members(
:param want_all:
""" # noqa: D400

attrib_names = (a.name for a in attr.fields(self.object) if a.init)
attrib_names = (a.name for a in attrs.fields(self.object) if a.init)

no_init_attribs = self.options.get("no-init-attribs", False)

Expand Down
10 changes: 5 additions & 5 deletions attr_utils/mypy_plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -141,15 +141,15 @@ def attr_utils_serialise_serde(cls_def_ctx: ClassDefContext) -> None:
#
# def attr__make_attrs(cls_def_ctx: ClassDefContext):
# """
# Handles :func:attr.ib`.
# Handles :func:attrs.field`.
#
# :param cls_def_ctx:
# """
#
# info = cls_def_ctx.cls.info
#
# list_ = cls_def_ctx.api.lookup_fully_qualified_or_none('typing.List')
# attribute = cls_def_ctx.api.lookup_fully_qualified_or_none('attr.Attribute')
# attribute = cls_def_ctx.api.lookup_fully_qualified_or_none('attrs.Attribute')
# #
# # if "__attrs_attrs__" not in info.names:
# # info.names["__attrs_attrs__"] = SymbolTableNode(
Expand All @@ -159,9 +159,9 @@ def attr_utils_serialise_serde(cls_def_ctx: ClassDefContext) -> None:
# # )

decorator_registry["attr_utils.serialise.serde"] = attr_utils_serialise_serde
# decorator_registry["attr._make.attrs"] = attr__make_attrs
# decorator_registry["attr.s"] = attr__make_attrs
# decorator_registry["attr.attrs"] = attr__make_attrs
# decorator_registry["attrs._make.attrs"] = attr__make_attrs
# decorator_registry["attrs.field"] = attr__make_attrs
# decorator_registry["attrs.attrs"] = attr__make_attrs


class AttrUtilsPlugin(Plugin):
Expand Down
10 changes: 5 additions & 5 deletions attr_utils/pprinter.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@
from typing import Any, Callable, Optional, Type, TypeVar, Union

# 3rd party
import attr
import attrs
from typing_extensions import Protocol, runtime_checkable

try:
Expand Down Expand Up @@ -175,21 +175,21 @@ def pretty_repr(obj: Type):
.. code-block:: python
>>> import attr
>>> import attrs
>>> from attr_utils.pprinter import pretty_repr
>>> @pretty_repr
... @attr.s
... @attrs.define
... class Person(object):
... name = attr.ib()
... name = attrs.field()
>>> repr(Person(name="Bob"))
Person(name='Bob')
:param obj:
"""

if attr.has(obj):
if attrs.has(obj):

def __repr__(self) -> str:
return prettyprinter.pformat(self)
Expand Down
Loading

0 comments on commit a584b92

Please sign in to comment.