Skip to content

Commit

Permalink
add some docstrings
Browse files Browse the repository at this point in the history
  • Loading branch information
mscarey committed Oct 14, 2021
1 parent 88ebd78 commit fbdb7c6
Show file tree
Hide file tree
Showing 5 changed files with 38 additions and 7 deletions.
6 changes: 6 additions & 0 deletions authorityspoke/decisions.py
Original file line number Diff line number Diff line change
Expand Up @@ -163,18 +163,21 @@ def get_majority(self) -> Optional[OpinionReading]:

@property
def holdings(self) -> HoldingGroup:
"""Get the holdings of this Decision's majority Opinion."""
if self.majority is not None:
return HoldingGroup(self.majority.holdings)
elif len(self.opinion_readings) == 1:
return HoldingGroup(self.opinion_readings[0].holdings)
return HoldingGroup()

def add_opinion(self, opinion: Opinion) -> None:
"""Link an Opinion document to this Decision."""
if not self.decision.casebody:
self.decision.casebody = CaseBody(data=CaseData())
self.decision.casebody.data.opinions.append(opinion)

def contradicts(self, other):
"""Check if a holding attributed to this decision contradicts a holding attributed in "other"."""
if isinstance(other, DecisionReading):
if self.majority and other.majority:
return self.majority.contradicts(other.majority)
Expand All @@ -184,6 +187,7 @@ def contradicts(self, other):
def explain_contradiction(
self, other: Union[OpinionReading, Holding, Rule]
) -> Optional[Explanation]:
"""Get the first generated explanation of how a Holding of self contradicts a Holding of other."""
explanations = self.explanations_contradiction(other)
try:
explanation = next(explanations)
Expand All @@ -195,6 +199,7 @@ def explanations_contradiction(
self,
other: Union[DecisionReading, Opinion, Holding, Rule],
) -> Iterator[Explanation]:
"""Generate explanations of how a Holding of self contradicts a Holding of other."""
if isinstance(other, DecisionReading):
if self.majority and other.majority:
yield from self.majority.explanations_contradiction(other.majority)
Expand All @@ -211,6 +216,7 @@ def explain_implication(
self,
other: Union[Opinion, Holding, Rule],
) -> Optional[Explanation]:
"""Get the first generated explanation of how a Holding of self implies a Holding of other."""
explanations = self.explanations_implication(other)
try:
explanation = next(explanations)
Expand Down
6 changes: 5 additions & 1 deletion authorityspoke/facts.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ class Config:

@root_validator(pre=True)
def nest_predicate_fields(cls, values):
"""Move fields passed to the Fact model that really belong to the Predicate model."""
type_str = values.pop("type", "")
if type_str and type_str.lower() != "fact":
raise ValidationError(f"type {type_str} was passed to Fact model")
Expand Down Expand Up @@ -125,7 +126,7 @@ def nest_predicate_fields(cls, values):

@validator("terms", pre=True)
def terms_as_sequence(cls, v, values) -> Sequence[Any]:

"""Convert "terms" field to a sequence."""
if isinstance(v, Mapping):
v = values["predicate"].template.get_term_sequence_from_mapping(v)
if not v:
Expand Down Expand Up @@ -284,6 +285,7 @@ def _contradicts_if_present(
) -> Iterator[Explanation]:
"""
Test if ``self`` contradicts :class:`Fact` ``other`` if neither is ``absent``.
:returns:
whether ``self`` and ``other`` can't both be true at
the same time under the given assumption.
Expand All @@ -306,6 +308,7 @@ def negated(self) -> Fact:
def new_context(self, changes: Dict[Comparable, Comparable]) -> Comparable:
"""
Create new :class:`Factor`, replacing keys of ``changes`` with values.
:returns:
a version of ``self`` with the new context.
"""
Expand All @@ -321,6 +324,7 @@ def _registers_for_interchangeable_context(
) -> Iterator[ContextRegister]:
r"""
Find possible combination of interchangeable :attr:`terms`.
:param matches:
matching Terms between self and other
:yields:
Expand Down
2 changes: 2 additions & 0 deletions authorityspoke/holdings.py
Original file line number Diff line number Diff line change
Expand Up @@ -652,13 +652,15 @@ def __str__(self):

class HoldingMatch(FactorMatch):
"""A logical relation between two holdings, e.g. implies, contradicts."""

left: Holding
operation: Callable
right: Holding


class HoldingGroup(FactorGroup):
"""Group of Holdings that can be compared as a group with other Holdings."""

term_class = Holding

def __init__(self, holdings: Union[Sequence[Holding], Holding] = ()):
Expand Down
27 changes: 21 additions & 6 deletions authorityspoke/io/readers.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

from anchorpoint.textselectors import TextQuoteSelector
from legislice.download import Client
from legislice.enactments import RawEnactment
from legislice.enactments import AnchoredEnactmentPassage, RawEnactment
from nettlesome.entities import Entity

from authorityspoke.decisions import Decision, DecisionReading, RawDecision
Expand Down Expand Up @@ -60,6 +60,7 @@ class HoldingsIndexed(NamedTuple):


def collect_anchors_from_index(object_index, field_name: str):
"""Get text anchors out of an index of terms or enactments."""
result = []
for key, value in object_index.items():
if value.get("anchors"):
Expand All @@ -86,10 +87,6 @@ def read_holdings_with_anchors(
:param client:
Legislice client for downloading missing fields from `record`
:param many:
a bool indicating whether to use the "many" form of the Marshmallow
schema (whether there are multiple Holdings)
:returns:
a namedtuple listing :class:`.Holding` objects with
a list matching :class:`.Holding`\s to selectors and
Expand Down Expand Up @@ -246,7 +243,25 @@ def expand_holdings(

def extract_anchors_from_holding_record(
record: List[RawHolding], client: Optional[Client] = None
):
) -> Tuple[
List[RawHolding],
List[EnactmentWithAnchors],
List[TermWithAnchors],
List[Dict[str, str]],
]:
r"""
Load a list of Holdings from JSON, with text links.
:param record:
a list of dicts representing holdings, in the JSON input format
:param client:
Legislice client for downloading missing fields from `record`
:returns:
a tuple of four objects containing holdings, terms, enactments,
and anchors.
"""
record_post_enactments, enactment_index = collect_enactments(record)
if client:
enactment_index_post_client = client.update_entries_in_enactment_index(
Expand Down
4 changes: 4 additions & 0 deletions authorityspoke/procedures.py
Original file line number Diff line number Diff line change
Expand Up @@ -694,12 +694,15 @@ def new_context(self, changes: ContextRegister) -> Procedure:
return self.__class__(**new_dict)

def set_inputs(self, factors: Sequence[Factor]) -> None:
"""Set factors required to invoke this Procedure."""
self.inputs = FactorGroup(factors).sequence

def set_despite(self, factors: Sequence[Factor]) -> None:
"""Set factors that do not preclude application of this Procedure."""
self.despite = FactorGroup(factors).sequence

def set_outputs(self, factors: Sequence[Factor]) -> None:
"""Set the outputs of this Procedure."""
self.outputs = FactorGroup(factors).sequence

def triggers_next_procedure(
Expand Down Expand Up @@ -745,6 +748,7 @@ def union(
other: Comparable,
context: Optional[Union[ContextRegister, Explanation]] = None,
) -> Optional[Comparable]:
"""Get a procedure with all the inputs and outputs of self and other."""
if not isinstance(context, Explanation):
context = Explanation.from_context(context)
explanations = self.explanations_union(other, context)
Expand Down

0 comments on commit fbdb7c6

Please sign in to comment.