Skip to content

Commit

Permalink
add Procedure.implies method as alias for __ge__
Browse files Browse the repository at this point in the history
  • Loading branch information
mscarey committed Jun 9, 2019
1 parent c4432da commit 5321d1b
Show file tree
Hide file tree
Showing 7 changed files with 87 additions and 73 deletions.
4 changes: 2 additions & 2 deletions authorityspoke/context.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,8 +80,8 @@ def log_mentioned_context(func: Callable):
If factor_record is a :class:`str` instead of a :class:`dict`, looks up the
corresponding factor in "mentioned" and returns that instead of
constructing a new :class:`Factor`. Also, if the newly-constructed
:class:`Factor` has a ``name`` attribute, logs the :class:`Factor`
constructing a new :class:`.Factor`. Also, if the newly-constructed
:class:`.Factor` has a ``name`` attribute, logs the :class:`.Factor`
in ``mentioned`` for later use.
"""

Expand Down
3 changes: 2 additions & 1 deletion authorityspoke/enactments.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ class Code:
}

def __init__(self, filename: str):
"""Set ``filename`` parameter as attribute."""
self.filename = filename

@property
Expand Down Expand Up @@ -360,7 +361,7 @@ def effective_date(self):
@property
def text(self):
"""
Get a passage from ``self``\s :class:`.Code` with ``self``\s :class:`.TextQuoteSelector`.
Get a passage from ``self``\'s :class:`.Code` with ``self``\'s :class:`.TextQuoteSelector`.
:returns: the full text of the cited passage from the XML.
"""
Expand Down
107 changes: 55 additions & 52 deletions authorityspoke/factors.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,17 +22,20 @@
@dataclass(frozen=True)
class Factor(ABC):
"""
Anything relevant to a court's determination of the applicability
of a legal :class:`.Rule` can be a :class:`Factor`. The same
:class:`Factor` that is in the outputs for the :class:`.Procedure`
of one legal :class:`.Rule` might be in the ``inputs`` of the
:class:`.Procedure` for another.
Things relevant to a :class:`.Court`\'s application of a :class:`.Rule`.
The same :class:`Factor` that is in the ``outputs`` for the
:class:`.Procedure` of one legal :class:`.Rule` might be in the
``inputs`` of the :class:`.Procedure` for another.
"""

@classmethod
def all_subclasses(cls) -> Set[Type]:
"""
:returns: the set of all subclasses of :class:`Factor`
Get all subclasses of :class:`Factor`.
:returns:
the set of all subclasses of :class:`Factor`
"""
return set(cls.__subclasses__()).union(
[s for c in cls.__subclasses__() for s in c.all_subclasses()]
Expand All @@ -42,11 +45,15 @@ def all_subclasses(cls) -> Set[Type]:
@functools.lru_cache()
def class_from_str(cls, name: str):
"""
Part of the JSON deserialization process. Obtains a classname
of a :class:`Factor` subclass from a string, checking first
in the lru_cache of known subclasses.
Find class for use in JSON deserialization process.
Obtains a classname of a :class:`Factor`
subclass from a string, checking first
in the ``lru_cache`` of known subclasses.
:param: name of the desired subclass
:param name: name of the desired subclass.
:returns: the Class named ``name``.
"""
name = name.capitalize()
class_options = {
Expand Down Expand Up @@ -79,8 +86,7 @@ def from_dict(
cls, factor_record: Dict, mentioned: List[Factor], regime: Optional["Regime"] = None
) -> Optional[Factor]:
"""
Turns a dict recently created from a chunk of JSON
into a :class:`Factor` object.
Turn fields from a chunk of JSON into a :class:`Factor` object.
:param factor_record:
parameter values to pass to :meth:`Factor.__init__`.
Expand Down Expand Up @@ -151,6 +157,8 @@ def generic_factors(self) -> List[Optional[Factor]]:
@property
def context_factors(self) -> Tuple:
"""
Get :class:`Factor`\s used in comparisons with other :class:`Factor`\s.
:returns:
a tuple of attributes that are designated as the ``context_factors``
for whichever subclass of :class:`Factor` calls this method. These
Expand All @@ -163,11 +171,11 @@ def context_factors(self) -> Tuple:
@property
def recursive_factors(self) -> Dict[Factor, None]:
"""
Collect ``self``'s :attr:`context_factors`, and each of their :attr:`context_factors`, recursively.
:returns:
a :class:`dict` (instead of a :class:`set`,
to preserve order) of :class:`Factor`\s including ``self``'s
:attr:`context_factors`, and each of those :class:`Factor`\s'
:attr:`context_factors`, recursively.
to preserve order) of :class:`Factor`\s.
"""
answers: Dict[Factor, None] = {self: None}
for context in filter(lambda x: x is not None, self.context_factors):
Expand Down Expand Up @@ -195,8 +203,7 @@ def _context_registers(
self, other: Factor, comparison: Callable
) -> Iterator[Dict[Factor, Factor]]:
"""
Searches through the :attr:`context_factors` of ``self``
and ``other``.
Search for ways to match :attr:`context_factors` of ``self`` and ``other``.
:yields:
all valid ways to make matches between
Expand All @@ -214,6 +221,8 @@ def _context_registers(

def contradicts(self, other: Optional[Factor]) -> bool:
"""
Test whether ``self`` implies the absence of ``other``.
:returns:
``True`` if self and other can't both be true at
the same time. Otherwise returns ``False``.
Expand All @@ -230,7 +239,7 @@ def contradicts(self, other: Optional[Factor]) -> bool:

def _contradicts_if_factor(self, other: Factor) -> bool:
"""
Tests whether ``self`` :meth:`implies` the absence of ``other``.
Test whether ``self`` :meth:`implies` the absence of ``other``.
This should only be called after confirming that ``other``
is not ``None``.
Expand All @@ -243,6 +252,8 @@ def _contradicts_if_factor(self, other: Factor) -> bool:

def evolve(self, changes: Union[str, Tuple[str, ...], Dict[str, Any]]) -> Factor:
"""
Make new object with attributes from ``self.__dict__``, replacing attributes as specified.
:param changes:
a :class:`dict` where the keys are names of attributes
of self, and the values are new values for those attributes, or
Expand Down Expand Up @@ -292,8 +303,9 @@ def means(self, other) -> bool:

def _equal_if_concrete(self, other: Factor) -> bool:
"""
Used to test equality based on :attr:`context_factors`,
usually after a subclasses has injected its own tests
Test equality based on :attr:`context_factors`.
Usually called after a subclasses has injected its own tests
based on other attributes.
:returns:
Expand All @@ -310,23 +322,19 @@ def _equal_if_concrete(self, other: Factor) -> bool:

def get_factor_by_name(self, name: str) -> Optional[Factor]:
"""
Performs a recursive search of ``self`` and ``self``'s attributes
for a :class:`Factor` with the specified ``name`` attribute.
Search of ``self`` and ``self``'s attributes for :class:`Factor` with specified ``name``.
:returns:
a :class:`Factor` with the specified ``name`` attribute
if it exists, otherwise returns ``None``.
if it exists, otherwise ``None``.
"""
for factor in self.recursive_factors:
if factor.name == name:
return factor
return None

def __ge__(self, other: Factor) -> bool:
"""
:returns:
bool indicating whether ``self`` implies ``other``.
"""
"""Test whether ``self`` implies ``other``."""
if other is None:
return True

Expand All @@ -345,11 +353,7 @@ def __ge__(self, other: Factor) -> bool:
return False

def __gt__(self, other: Optional[Factor]) -> bool:
"""
:returns:
bool indicating whether ``self`` implies ``other``
and ``self`` != ``other``.
"""
"""Test whether ``self`` implies ``other`` and ``self`` != ``other``."""
return self >= other and self != other

def implies(self, other: Factor) -> bool:
Expand Down Expand Up @@ -400,6 +404,8 @@ def _implies_if_present(self, other: Factor) -> bool:

def make_generic(self) -> Factor:
"""
Get a copy of ``self`` except ensure ``generic`` is ``True``.
.. note::
The new object created with this method will have all the
attributes of ``self`` except ``generic=False``.
Expand All @@ -414,6 +420,8 @@ def make_generic(self) -> Factor:
@new_context_helper
def new_context(self, changes: Dict[Factor, Factor]) -> Factor:
"""
Create new :class:`Factor`, replacing keys of ``changes`` with values.
:param changes:
has :class:`.Factor`\s to replace as keys, and has
their replacements as the corresponding values.
Expand All @@ -434,6 +442,8 @@ def _registers_for_interchangeable_context(
self, matches: Dict[Factor, Factor]
) -> Iterator[Dict[Factor, Factor]]:
"""
Find possible combination of interchangeable :attr:`context_factors`.
:yields:
context registers with every possible combination of
``self``'s and ``other``'s interchangeable
Expand Down Expand Up @@ -469,18 +479,7 @@ def _import_to_mapping(
self_mapping: Dict[Factor, Factor], incoming_mapping: Dict[Factor, Factor]
) -> Optional[Dict[Factor, Factor]]:
"""
Compares :class:`Factor`\s based on their :meth:`__repr__` to
determine whether two sets of matches of :class:`Factor`\s
can be merged.
:meth:`__repr__` was chosen because an ``is`` test would
return ``False`` when the :class:`Factor`\s are equal but
not identical, while :meth:`__eq__` incorrectly matches
generically equal :class:`Factor`\s that don't refer to the
same thing.
This problem is a consequence of overloading the :meth:`__eq__`
operator.
Compare :class:`Factor`\s to test if two sets of matches can be merged.
:param self_mapping:
an existing mapping of :class:`Factor`\s
Expand Down Expand Up @@ -523,6 +522,8 @@ def update_context_register(
self, other: Factor, register: Dict[Factor, Factor], comparison: Callable
):
"""
Find ways to update ``self_mapping`` to allow relationship ``comparison``.
:param other:
another :class:`Factor` being compared to ``self``
Expand All @@ -538,7 +539,7 @@ def update_context_register(
:yields:
every way that ``self_mapping`` can be updated to be consistent
with ``self`` and ``other`` having the relationship
``comparison``
``comparison``.
"""
if other and not isinstance(other, Factor):
raise TypeError(f"{other} is type {other.__class__.__name__}, not Factor")
Expand All @@ -558,8 +559,9 @@ def _wrap_with_tuple(item):
@dataclass(frozen=True)
class Fact(Factor):
"""
An assertion accepted as factual by a court, often
through factfinding by a judge or jury.
An assertion accepted as factual by a court.
Often based on factfinding by a judge or jury.
:param predicate:
a natural-language clause with zero or more slots
Expand Down Expand Up @@ -1000,16 +1002,17 @@ class Exhibit(Factor):
"""
A source of information for use in litigation.
"derived_from" and and "offered_by" parameters were removed
because the former is probably better represented as a :class:`Fact`,
and the latter as a :class:`Motion`.
.. note
"Derived_from" and "offered_by" parameters were removed
because the former is probably better represented as a :class:`Fact`,
and the latter as a :class:`Motion`.
TODO: Allowed inputs for ``form`` will need to be limited.
"""

form: Optional[str] = None
statement: Optional[Fact] = None
stated_by: Optional["Entity"] = None
stated_by: Optional[Entity] = None
name: Optional[str] = None
absent: bool = False
generic: bool = False
Expand Down Expand Up @@ -1115,7 +1118,7 @@ def means(self, other):
"""
Test whether ``other`` has the same meaning as ``self``.
``generic`` :class:`Entity` objects are considered equivalent
``Generic`` :class:`Entity` objects are considered equivalent
in meaning as long as they're the same class. If not ``generic``,
they're considered equivalent if all their attributes are the same.
"""
Expand Down
10 changes: 5 additions & 5 deletions authorityspoke/jurisdictions.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,14 +69,14 @@ class Regime:
Currently used for retrieving :class:`.Enactment` text.
May be modified for retrieving :class:`.Court`\s and
:class:`.Opinion`\s
:class:`.Opinion`\s.
"""

jurisdictions: Dict[str, Jurisdiction] = field(default_factory=dict)

def get_code(self, selector: Union[TextQuoteSelector, str]):
"""
Find a :class:`.Code` in the Regime from a selector.
Find a :class:`.Code` in the :class:`Regime` from a selector.
:returns:
the :class:`.Code` described in the selector path.
Expand All @@ -98,13 +98,13 @@ def get_code(self, selector: Union[TextQuoteSelector, str]):

def set_code(self, code: Code) -> None:
"""
Add to the collection of :class:`.Code`\s enacted in this Regime.
Add to the collection of :class:`.Code`\s enacted in this :class:`Regime`.
Create the appropriate :class:`.Jurisdiction` object for the
:class:`.Code`, if it's not already linked to the Regime.
:class:`.Code`, if it's not already linked to the :class:`Regime`.
:param code:
a :class:`.Code` valid in this Regime
a :class:`.Code` valid in this :class:`Regime`
"""
if code.jurisdiction not in self.jurisdictions:
self.jurisdictions[code.jurisdiction] = Jurisdiction()
Expand Down
13 changes: 7 additions & 6 deletions authorityspoke/predicates.py
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,8 @@ def means(self, other) -> bool:

def __gt__(self, other: Optional[Predicate]) -> bool:
"""
Test whether ``self`` implies ``other`` and has different meaning.
:returns:
whether ``self`` implies ``other``, which is ``True``
if their statements about quantity imply it.
Expand Down Expand Up @@ -308,6 +310,8 @@ def __len__(self):

def quantity_comparison(self) -> str:
"""
Convert text to a comparison with a quantity.
:returns:
string representation of a comparison with a
quantity, which can include units due to the
Expand All @@ -328,12 +332,7 @@ def quantity_comparison(self) -> str:
return f"{expand[comparison]} {self.quantity}"

def negated(self) -> Predicate:
"""
:returns:
a copy of the same :class:`Predicate`,
but with the opposite truth value.
"""

"""Copy ``self``, with the opposite truth value."""
return Predicate(
content=self.content,
truth=not self.truth,
Expand All @@ -359,6 +358,8 @@ def __str__(self):
@staticmethod
def str_to_quantity(quantity: str) -> Union[float, int, ureg.Quantity]:
"""
Create `pint <https://pint.readthedocs.io/en/0.9/tutorial.html>`_ quantity object from text.
:param quantity:
when a string is being parsed for conversion to a
:class:`Predicate`, this is the part of the string
Expand Down

0 comments on commit 5321d1b

Please sign in to comment.