def posit_holding( self, holding: Union[Holding, Rule], holding_anchors: Optional[Union[TextQuoteSelector, List[TextQuoteSelector]]] = None, named_anchors: Optional[TextLinkDict] = None, context: Optional[Sequence[Factor]] = None, ) -> None: r"""Record that this Opinion endorses specified :class:`Holding`\s.""" if holding_anchors and not isinstance(holding_anchors, List): holding_anchors = [holding_anchors] if isinstance(holding, Rule): logger.warning("posit_holding was called with a Rule " "that was automatically converted to a Holding") holding = Holding(rule=holding) if not isinstance(holding, Holding): raise TypeError('"holding" must be an object of type Holding.') if context: holding = holding.new_context(context, context_opinion=self) self.holding_anchors[holding].extend(holding_anchors or []) if named_anchors: for factor in (list(holding.recursive_factors) + list(holding.enactments) + list(holding.enactments_despite)): if hasattr(factor, "name") and factor.name in named_anchors: for anchor in named_anchors[factor.name]: if anchor not in self.factors[factor]: self.factors[factor].append(anchor)
def implied_by_holding(self, other: Holding, context: ContextRegister = None) -> bool: context = context or ContextRegister() return all( other.implies(self_holding, context=context.reversed()) for self_holding in self.holdings)
def implied_by_holding(self, other: Holding) -> Iterator[Explanation]: if all(other.implies(self_holding) for self_holding in self.holdings): yield Explanation( matches=[(other, self_holding) for self_holding in self.holdings], operation=operator.ge, )
def extract_anchors_from_holding_record( record: List[RawHolding], client: Optional[Client] = None ) -> Tuple[List[Holding], 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( enactment_index) else: enactment_index_post_client = enactment_index enactment_anchors, enactment_index_post_anchors = collect_anchors_from_index( enactment_index_post_client, "passage") enactment_result = [] for anchor in enactment_anchors: anchor["passage"] = enactment_index_post_anchors.get_if_present( anchor["passage"]) enactment_result.append(EnactmentWithAnchors(**anchor)) record_post_terms, factor_index = index_names(record_post_enactments) factor_anchors, factor_index_post_anchors = collect_anchors_from_index( factor_index, "term") factor_result = [] for anchor in factor_anchors: anchor["term"] = expand_holding( anchor["term"], factor_index=factor_index_post_anchors, enactment_index=enactment_index_post_anchors, ) factor_result.append(TermWithAnchors(**anchor)) factor_anchors = [TermWithAnchors(**anchor) for anchor in factor_anchors] expanded = expand_holdings( record_post_terms, factor_index=factor_index_post_anchors, enactment_index=enactment_index_post_anchors, ) holding_anchors = [holding.pop("anchors", None) for holding in expanded] result = [] for holding in expanded: result.append(Holding(**holding)) return result, enactment_result, factor_result, holding_anchors
def test_implies_holding(self, make_complex_rule): """ The Rule class doesn't know anything about the Holding class, but it should check whether Holding has an is_implied_by method and call it. """ small_reliable = make_complex_rule["accept_small_weight_reliable"] small_more_reliable_holding = Holding(rule=make_complex_rule[ "accept_small_weight_reliable_more_evidence"]) assert small_reliable >= small_more_reliable_holding
def test_dump_and_load_holding(self, fake_usc_client, make_holding): """Dump holding and load it as if it was a JSON API response.""" holding = make_holding["h2"] dumped = holding.dict() content = dumped["rule"]["procedure"]["inputs"][1]["predicate"][ "content"] assert content == "$thing was a stockpile of Christmas trees" loaded = Holding(**dumped) loaded_content = loaded.inputs[0].predicate.content assert "$thing was on the premises of $place" in loaded_content
def implied_by_holding( self, other: Holding, context: Optional[ContextRegister] = None ) -> Iterator[Explanation]: """Check if a Holding implies all the Holdings of self.""" if all( other.implies(self_holding, context=context) for self_holding in self.holdings ): yield Explanation( reasons=[(other, self_holding) for self_holding in self.holdings], operation=operator.ge, )
def test_does_not_imply_holding_due_to_context(self, make_complex_rule): """ The Rule class doesn't know anything about the Holding class, but it should check whether Holding has an is_implied_by method and call it. """ small_reliable = make_complex_rule["accept_small_weight_reliable"] small_more_reliable_holding = Holding(rule=make_complex_rule[ "accept_small_weight_reliable_more_evidence"]) assert not small_reliable.implies( small_more_reliable_holding, context=ContextRegister.from_lists([Entity(name="Alice")], [Entity(name="Bob")]), )
def explanations_implied_by(self, other: Comparable, context: Optional[ContextRegister] = None ) -> Iterator[Explanation]: context = context or ContextRegister() if isinstance(other, Opinion): other = other.holdings if isinstance(other, HoldingGroup): yield from other.explanations_implication( self.holdings, context=context.reversed()) if isinstance(other, Rule): other = Holding(rule=other) if isinstance(other, Holding): yield from self.implied_by_holding(other, context)
def test_getting_factors_from_new_holding(self, make_opinion_with_holding): watt = make_opinion_with_holding["watt_majority"] watt.clear_holdings() elephants = Fact(predicate="$animal was an elephant", terms=Entity(name="the elephant")) mouseholes = Fact( predicate=Predicate(content="$animal hides in mouseholes", truth=False), terms=Entity(name="the elephant"), ) procedure = Procedure(inputs=elephants, outputs=mouseholes) rule = Rule(procedure=procedure) holding = Holding(rule=rule) watt.posit(holding) factors = watt.factors_by_name() factor = factors["the fact that <the elephant> was an elephant"] assert factor.terms[0].name == "the elephant"
def posit_holding( self, holding: Union[Holding, Rule, HoldingWithAnchors], holding_anchors: Optional[Union[TextPositionSelector, TextQuoteSelector, TextPositionSet]] = None, named_anchors: Optional[List[TermWithAnchors]] = None, enactment_anchors: Optional[List[EnactmentWithAnchors]] = None, context: Optional[Sequence[Factor]] = None, ) -> None: r"""Record that this Opinion endorses specified :class:`Holding`\s.""" named_anchors = named_anchors or [] enactment_anchors = enactment_anchors or [] if isinstance(holding, HoldingWithAnchors): holding, holding_anchors = holding.holding, holding.anchors if isinstance(holding_anchors, (TextQuoteSelector, str)): holding_anchors = [holding_anchors] if isinstance(holding_anchors, List) and isinstance( holding_anchors[0], (str, TextQuoteSelector)): holding_anchors = TextPositionSet.from_quotes(holding_anchors) if isinstance(holding, Rule): logger.warning("posit_holding was called with a Rule " "that was automatically converted to a Holding") holding = Holding(rule=holding) if not isinstance(holding, Holding): raise TypeError('"holding" must be an object of type Holding.') for named_anchor in named_anchors: self.anchored_holdings.add_term(term=named_anchor.term, anchors=named_anchor.anchors) for enactment_anchor in enactment_anchors: self.anchored_holdings.add_enactment( enactment=enactment_anchor.passage, anchors=named_anchor.anchors) matching_holding = self.get_matching_holding(holding) if matching_holding: matching_holding.anchors += holding.anchors else: if context: holding = holding.new_context(context, source=self) self.anchored_holdings.holdings.append( HoldingWithAnchors(holding=holding, anchors=holding_anchors))
def explanations_implication( self, other: Comparable, ) -> Iterator[Union[ContextRegister, Explanation]]: """Yield contexts that would result in self implying other.""" if not self.comparable_with(other): raise TypeError( f"'Implies' test not implemented for types {self.__class__} and {other.__class__}." ) if isinstance(other, Rule): other = Holding(rule=other) if isinstance(other, Holding): for self_holding in self.holdings: yield from self_holding.explanations_implication(other) if isinstance(other, HoldingGroup): yield from self.holdings.explanations_implication(other) elif isinstance(other, self.__class__): yield from self.holdings.explanations_implication(other.holdings) else: yield from other.explanations_implied_by(self)
def explanations_contradiction( self, other: Comparable, ) -> Iterator[Explanation]: """Yield contexts that would result in a contradiction between self and other.""" if not self.comparable_with(other): raise TypeError( f"'Implies' test not implemented for types {self.__class__} and {other.__class__}." ) if isinstance(other, Rule): other = Holding(rule=other) if isinstance(other, Holding): yield from self.holdings.explanations_contradiction(other) if isinstance(other, HoldingGroup): yield from self.holdings.explanations_contradiction(other) elif isinstance(other, self.__class__): yield from self.holdings.explanations_contradiction(other.holdings) elif hasattr(other, "explanations_contradiction"): yield from other.explanations_contradiction(self)
def explanations_implication( self, other: Comparable, context: Optional[ContextRegister] = None ) -> Iterator[Union[ContextRegister, Explanation]]: """Yield contexts that would result in self implying other.""" if isinstance(other, Rule): other = Holding(rule=other) if isinstance(other, Holding): for self_holding in self.holdings: for explanation in self_holding.explanations_implication( other, context): yield explanation elif isinstance(other, self.__class__): yield from self.holdings.explanations_implication(other.holdings, context=context) elif hasattr(other, "explanations_implication"): if context: context = context.reversed() yield from other.explanations_implication(self, context=context) else: raise TypeError( f"'Implies' test not implemented for types {self.__class__} and {other.__class__}." )
def explanations_contradiction( self, other: Comparable, context: Optional[ContextRegister] = None, ) -> Iterator[Explanation]: """Yield contexts that would result in a contradiction between self and other.""" if isinstance(other, Rule): other = Holding(rule=other) if isinstance(other, Holding): for self_holding in self.holdings: for explanation in self_holding.explanations_contradiction( other, context): yield explanation elif isinstance(other, self.__class__): for self_holding in self.holdings: for other_holding in other.holdings: for explanation in self_holding.explanations_contradiction( other_holding, context): yield explanation elif hasattr(other, "explanations_contradiction"): yield from other.explanations_contradiction(self) else: raise TypeError(f"'Contradicts' test not implemented for types " + f"{self.__class__} and {other.__class__}.")
def _implied_by_rule(self, other: Rule, context: Explanation) -> bool: return self._implied_by_holding(other=Holding(rule=other), context=context)
def _implied_by_holding(self, other: Holding, context: Explanation) -> bool: return all( other.implies(self_holding, context=context.reversed_context()) for self_holding in self.holdings)
def get_matching_holding(self, holding: Holding) -> Optional[Holding]: """Check self's Holdings for a Holding with the same meaning.""" for known_holding in self.holdings: if holding.means(known_holding): return known_holding return None
def test_fact_in_spec(self): spec = Holding.schema() assert "Fact" in spec["definitions"]
def implies_rule(self, other: Rule, context: Optional[ContextRegister] = None) -> bool: return self.implies_holding(Holding(other), context=context)
def implied_by_rule(self, other: Rule, context: ContextRegister = None) -> bool: return self.implied_by_holding(other=Holding(other), context=context)
def implies_rule( self, other: Rule, context: Optional[ContextRegister] = None ) -> bool: """Check if a Holding of self implies a Holding made from other Rule.""" return self.implies_holding(Holding(rule=other), context=context)
def test_factor_one_of(self): spec = Holding.schema() factor_schema = spec["definitions"]["Procedure"]["properties"][ "outputs"] assert "anyOf" in factor_schema["items"]