Skip to content

Commit

Permalink
chore: switch to new import attrs API (#152)
Browse files Browse the repository at this point in the history
* chore: remove redundant attrs.field() calls
* chore: simplify _new_type_to_xref in Sphinx <4.4
* ci: run pre-commit pylint hook serial
* fix: provide custom JSON encoder for sets
* fix: run update cron job on Mondays
  • Loading branch information
redeboer authored Feb 19, 2022
1 parent a7e2637 commit 63c08cb
Show file tree
Hide file tree
Showing 24 changed files with 299 additions and 280 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/requirements-cron.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ name: Requirements (scheduled)

on:
schedule:
- cron: "0 2 */14 * *"
- cron: "0 2 * * 1"
workflow_dispatch:

jobs:
Expand Down
1 change: 1 addition & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -183,5 +183,6 @@ repos:
- --rcfile=.pylintrc
- --score=no
language: system
require_serial: true
types:
- python
7 changes: 7 additions & 0 deletions .pylintrc
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,20 @@ ignore-patterns=
[MESSAGES CONTROL]
disable=
duplicate-code, # https://github.com/PyCQA/pylint/issues/214
invalid-unary-operand-type, # conflicts with attrs.field
logging-fstring-interpolation,
missing-class-docstring, # pydocstyle
missing-function-docstring, # pydocstyle
missing-module-docstring, # pydocstyle
no-member, # conflicts with attrs.field
not-an-iterable, # conflicts with attrs.field
not-callable, # conflicts with attrs.field
redefined-builtin, # flake8-built
too-few-public-methods, # data containers (attrs) and interface classes
unspecified-encoding, # http://pylint.pycqa.org/en/latest/whatsnew/2.10.html
unsubscriptable-object, # conflicts with attrs.field
unsupported-assignment-operation, # conflicts with attrs.field
unsupported-membership-test, # conflicts with attrs.field
unused-import, # https://www.flake8rules.com/rules/F401

[SIMILARITIES]
Expand Down
41 changes: 19 additions & 22 deletions docs/_relink_references.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
# cspell:ignore docutils
# pylint: disable=import-error, import-outside-toplevel
# pyright: reportMissingImports=false
"""Abbreviated the annotations generated by sphinx-autodoc.
Expand All @@ -16,28 +15,22 @@
from sphinx.environment import BuildEnvironment


def _replace_link(text: str) -> str:
replacements = {
"a set-like object providing a view on D's items": "typing.ItemsView",
"a set-like object providing a view on D's keys": "typing.KeysView",
"an object providing a view on D's values": "typing.ValuesView",
"typing_extensions.Protocol": "typing.Protocol",
}
for old, new in replacements.items():
if text == old:
return new
return text
__TARGET_SUBSTITUTIONS = {
"a set-like object providing a view on D's items": "typing.ItemsView",
"a set-like object providing a view on D's keys": "typing.KeysView",
"an object providing a view on D's values": "typing.ValuesView",
"typing_extensions.Protocol": "typing.Protocol",
}
__REF_TYPE_SUBSTITUTIONS = {
"None": "obj",
}


def _new_type_to_xref(
text: str, env: "BuildEnvironment" = None
target: str,
env: "BuildEnvironment" = None,
suppress_prefix: bool = False,
) -> "pending_xref":
"""Convert a type string to a cross reference node."""
if text == "None":
reftype = "obj"
else:
reftype = "class"

if env:
kwargs = {
"py:module": env.ref_context.get("py:module"),
Expand All @@ -46,8 +39,12 @@ def _new_type_to_xref(
else:
kwargs = {}

text = _replace_link(text)
short_text = text.split(".")[-1]
target = __TARGET_SUBSTITUTIONS.get(target, target)
reftype = __REF_TYPE_SUBSTITUTIONS.get(target, "class")
if suppress_prefix:
short_text = target.split(".")[-1]
else:
short_text = target

from docutils.nodes import Text
from sphinx.addnodes import pending_xref
Expand All @@ -57,7 +54,7 @@ def _new_type_to_xref(
Text(short_text),
refdomain="py",
reftype=reftype,
reftarget=text,
reftarget=target,
**kwargs,
)

Expand Down
1 change: 1 addition & 0 deletions docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,7 @@ def fetch_logo(url: str, output_path: str) -> None:
("py:class", "NoneType"),
("py:class", "StateTransitionGraph"),
("py:class", "ValueType"),
("py:class", "json.encoder.JSONEncoder"),
("py:class", "typing_extensions.Protocol"),
("py:obj", "qrules.topology._K"),
("py:obj", "qrules.topology._V"),
Expand Down
6 changes: 3 additions & 3 deletions docs/usage/conservation.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@
},
"outputs": [],
"source": [
"import attr\n",
"import attrs\n",
"import graphviz\n",
"\n",
"import qrules\n",
Expand Down Expand Up @@ -377,7 +377,7 @@
"metadata": {},
"outputs": [],
"source": [
"new_interaction = attr.evolve(transition.interactions[node_id], l_magnitude=2)\n",
"new_interaction = attrs.evolve(transition.interactions[node_id], l_magnitude=2)\n",
"new_interaction"
]
},
Expand All @@ -396,7 +396,7 @@
"source": [
"new_interaction_dict = dict(transition.interactions) # make mutable\n",
"new_interaction_dict[node_id] = new_interaction\n",
"new_transition = attr.evolve(transition, interactions=new_interaction_dict)"
"new_transition = attrs.evolve(transition, interactions=new_interaction_dict)"
]
},
{
Expand Down
4 changes: 2 additions & 2 deletions src/qrules/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
Union,
)

import attr
import attrs

from . import io
from .combinatorics import InitialFacts, StateDefinition, create_initial_facts
Expand Down Expand Up @@ -237,7 +237,7 @@ def check_edge_qn_conservation() -> Set[FrozenSet[str]]:
initial_facts_list = []
for ls_combi in ls_combinations:
for facts_combination in initial_facts:
new_facts = attr.evolve(
new_facts = attrs.evolve(
facts_combination,
node_props={node_id: ls_combi},
)
Expand Down
8 changes: 4 additions & 4 deletions src/qrules/_implementers.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

from typing import TYPE_CHECKING, Any, Callable, Type, TypeVar

import attr
import attrs

if TYPE_CHECKING:
try:
Expand All @@ -17,12 +17,12 @@
def implement_pretty_repr() -> Callable[
[Type[_DecoratedClass]], Type[_DecoratedClass]
]:
"""Implement a pretty :code:`repr` in a `attr` decorated class."""
"""Implement a pretty :code:`repr` in a class decorated by `attrs`."""

def decorator(
decorated_class: Type[_DecoratedClass],
) -> Type[_DecoratedClass]:
if not attr.has(decorated_class):
if not attrs.has(decorated_class):
raise TypeError(
"Can only implement a pretty repr for a class created with"
" attrs"
Expand All @@ -34,7 +34,7 @@ def repr_pretty(self: Any, p: "PrettyPrinter", cycle: bool) -> None:
p.text(f"{class_name}(...)")
else:
with p.group(indent=2, open=f"{class_name}("):
for field in attr.fields(type(self)):
for field in attrs.fields(type(self)):
if not field.init:
continue
value = getattr(self, field.name)
Expand Down
20 changes: 10 additions & 10 deletions src/qrules/_system_control.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from abc import ABC, abstractmethod
from typing import Callable, Dict, Iterable, List, Optional, Set, Tuple, Type

import attr
import attrs

from .particle import Particle, ParticleCollection, ParticleWithSpin
from .quantum_numbers import (
Expand Down Expand Up @@ -34,10 +34,10 @@ def create_edge_properties(
qn_name: qn_type
for qn_name, qn_type in EdgeQuantumNumbers.__dict__.items()
if not qn_name.startswith("__")
} # Note using attr.fields does not work here because init=False
} # Note using attrs.fields does not work here because init=False
property_map: GraphEdgePropertyMap = {}
isospin = None
for qn_name, value in attr.asdict(particle, recurse=False).items():
for qn_name, value in attrs.asdict(particle, recurse=False).items():
if isinstance(value, Parity):
value = value.value
if qn_name in edge_qn_mapping:
Expand Down Expand Up @@ -65,9 +65,9 @@ def create_node_properties(
qn_name: qn_type
for qn_name, qn_type in NodeQuantumNumbers.__dict__.items()
if not qn_name.startswith("__")
} # Note using attr.fields does not work here because init=False
} # Note using attrs.fields does not work here because init=False
property_map: GraphNodePropertyMap = {}
for qn_name, value in attr.asdict(node_props).items():
for qn_name, value in attrs.asdict(node_props).items():
if value is None:
continue
if qn_name in node_qn_mapping:
Expand Down Expand Up @@ -117,11 +117,11 @@ def create_interaction_properties(
converted_solution = {k.__name__: v for k, v in qn_solution.items()}
kw_args = {
x.name: converted_solution[x.name]
for x in attr.fields(InteractionProperties)
for x in attrs.fields(InteractionProperties)
if x.name in converted_solution
}

return attr.evolve(InteractionProperties(), **kw_args)
return attrs.evolve(InteractionProperties(), **kw_args)


def filter_interaction_types(
Expand Down Expand Up @@ -234,7 +234,7 @@ def _remove_qns_from_graph( # pylint: disable=too-many-branches
new_node_props = {}
for node_id in graph.topology.nodes:
node_props = graph.get_node_props(node_id)
new_node_props[node_id] = attr.evolve(
new_node_props[node_id] = attrs.evolve(
node_props, **{x.__name__: None for x in qn_list}
)

Expand Down Expand Up @@ -279,10 +279,10 @@ def __call__(
node_props1: InteractionProperties,
node_props2: InteractionProperties,
) -> bool:
return attr.evolve(
return attrs.evolve(
node_props1,
**{x.__name__: None for x in self.__ignored_qn_list},
) == attr.evolve(
) == attrs.evolve(
node_props2,
**{x.__name__: None for x in self.__ignored_qn_list},
)
Expand Down
14 changes: 7 additions & 7 deletions src/qrules/argument_handling.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
Union,
)

import attr
import attrs

from .conservation_rules import (
ConservationRule,
Expand Down Expand Up @@ -154,7 +154,7 @@ def __init__(self, class_type: type) -> None:
)
if _is_edge_quantum_number(class_field.type)
else _ValueExtractor[NodeQuantumNumber](class_field.type)
for class_field in attr.fields(class_type)
for class_field in attrs.fields(class_type)
}

def __call__(
Expand Down Expand Up @@ -206,10 +206,10 @@ def __create_requirements_check(
qn_type = input_type.__args__[0] # type: ignore[attr-defined]
is_list = True

if attr.has(qn_type):
if attrs.has(qn_type):
class_field_types = [
class_field.type
for class_field in attr.fields(qn_type)
for class_field in attrs.fields(qn_type)
if not _is_optional(class_field.type)
]
qn_check_function: Callable[
Expand Down Expand Up @@ -239,7 +239,7 @@ def __create_argument_builder(
qn_type = input_type.__args__[0] # type: ignore[attr-defined]
is_list = True

if attr.has(qn_type):
if attrs.has(qn_type):
arg_builder: Callable[..., Any] = _CompositeArgumentCreator(
qn_type
)
Expand Down Expand Up @@ -322,8 +322,8 @@ def get_required_qns(
if _is_sequence_type(input_type):
class_type = input_type.__args__[0]

if attr.has(class_type):
for class_field in attr.fields(class_type):
if attrs.has(class_type):
for class_field in attrs.fields(class_type):
field_type = (
class_field.type.__args__[0] # type: ignore[union-attr]
if _is_optional(class_field.type)
Expand Down
8 changes: 4 additions & 4 deletions src/qrules/combinatorics.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
Union,
)

import attr
from attrs import field, frozen

from qrules._implementers import implement_pretty_repr
from qrules.particle import Particle, ParticleCollection
Expand All @@ -38,10 +38,10 @@


@implement_pretty_repr()
@attr.frozen
@frozen
class InitialFacts:
edge_props: Dict[int, ParticleWithSpin] = attr.ib(factory=dict)
node_props: Dict[int, InteractionProperties] = attr.ib(factory=dict)
edge_props: Dict[int, ParticleWithSpin] = field(factory=dict)
node_props: Dict[int, InteractionProperties] = field(factory=dict)


class _KinematicRepresentation:
Expand Down
Loading

0 comments on commit 63c08cb

Please sign in to comment.