caselawclient.models.identifiers.neutral_citation
1import re 2 3from ds_caselaw_utils import neutral_url 4from ds_caselaw_utils.types import NeutralCitationString 5 6from caselawclient.types import DocumentIdentifierSlug 7 8from . import Identifier, IdentifierSchema 9from .exceptions import IdentifierValidationException 10 11VALID_NCN_PATTERN = re.compile(r"(^\[([0-9]{4})\] ([a-zA-Z]+)(?: ([a-zA-Z]+))? ([0-9]+)(?: \(([a-zA-Z0-9]+)\))?$)") 12""" 13This is a catch-all pattern for anything which looks like a Neutral Citation, even if the court itself isn't valid. Checking that an NCN is plausibly correct is handled elsewhere. 14 15This pattern also defines five capture groups to standardise how we interface with the elements: 16 17- `0`: The year of the decision 18- `1`: The court 19- `2`: (Optionally) the jurisdiction or division, depending on the court 20- `3`: The sequence number of the decision 21- `4`: (Optionally) the jurisdiction or division, depending on the court 22 23TODO: When these capture groups are being used in anger (eg to build URL slugs) you should go through and name the groups. 24""" 25 26 27class NCNValidationException(IdentifierValidationException): 28 pass 29 30 31class NCNDoesNotMatchExpectedPatternException(NCNValidationException): 32 pass 33 34 35class NCNCannotConvertToValidURLSlugException(NCNValidationException): 36 pass 37 38 39class NeutralCitationNumberSchema(IdentifierSchema): 40 """ 41 Identifier schema describing a Neutral Citation Number. 42 43 https://www.iclr.co.uk/knowledge/case-law/neutral-citations/ 44 """ 45 46 name = "Neutral Citation Number" 47 namespace = "ukncn" 48 human_readable = True 49 base_score_multiplier = 1.5 50 51 document_types = ["Judgment"] 52 53 @classmethod 54 def validate_identifier_value(cls, value: str) -> bool: 55 # Quick check to see if the NCN matches the expected pattern 56 if not bool(VALID_NCN_PATTERN.match(value)): 57 raise NCNDoesNotMatchExpectedPatternException(f"NCN '{value}' is not in the expected format") 58 59 # Can we convert this to a URL? neutral_url returns False if not. 60 # This functionally tests to see if the court exists, since only valid patterns (where we know how to match the court code) will convert 61 if not neutral_url(NeutralCitationString(value)): 62 raise NCNCannotConvertToValidURLSlugException(f"NCN '{value}' cannot be converted to an NCN-based URL slug") 63 64 return True 65 66 @classmethod 67 def compile_identifier_url_slug(cls, value: str) -> DocumentIdentifierSlug: 68 ncn_based_uri_string = neutral_url( 69 NeutralCitationString(value) 70 ) # TODO: At some point this should move out of utils and into this class. 71 if not ncn_based_uri_string: 72 raise NCNCannotConvertToValidURLSlugException(f"NCN '{value}' cannot be converted to an NCN-based URL slug") 73 return DocumentIdentifierSlug(ncn_based_uri_string) 74 75 76class NeutralCitationNumber(Identifier): 77 schema = NeutralCitationNumberSchema
This is a catch-all pattern for anything which looks like a Neutral Citation, even if the court itself isn't valid. Checking that an NCN is plausibly correct is handled elsewhere.
This pattern also defines five capture groups to standardise how we interface with the elements:
0: The year of the decision1: The court2: (Optionally) the jurisdiction or division, depending on the court3: The sequence number of the decision4: (Optionally) the jurisdiction or division, depending on the court
TODO: When these capture groups are being used in anger (eg to build URL slugs) you should go through and name the groups.
Common base class for all non-exit exceptions.
Common base class for all non-exit exceptions.
Common base class for all non-exit exceptions.
40class NeutralCitationNumberSchema(IdentifierSchema): 41 """ 42 Identifier schema describing a Neutral Citation Number. 43 44 https://www.iclr.co.uk/knowledge/case-law/neutral-citations/ 45 """ 46 47 name = "Neutral Citation Number" 48 namespace = "ukncn" 49 human_readable = True 50 base_score_multiplier = 1.5 51 52 document_types = ["Judgment"] 53 54 @classmethod 55 def validate_identifier_value(cls, value: str) -> bool: 56 # Quick check to see if the NCN matches the expected pattern 57 if not bool(VALID_NCN_PATTERN.match(value)): 58 raise NCNDoesNotMatchExpectedPatternException(f"NCN '{value}' is not in the expected format") 59 60 # Can we convert this to a URL? neutral_url returns False if not. 61 # This functionally tests to see if the court exists, since only valid patterns (where we know how to match the court code) will convert 62 if not neutral_url(NeutralCitationString(value)): 63 raise NCNCannotConvertToValidURLSlugException(f"NCN '{value}' cannot be converted to an NCN-based URL slug") 64 65 return True 66 67 @classmethod 68 def compile_identifier_url_slug(cls, value: str) -> DocumentIdentifierSlug: 69 ncn_based_uri_string = neutral_url( 70 NeutralCitationString(value) 71 ) # TODO: At some point this should move out of utils and into this class. 72 if not ncn_based_uri_string: 73 raise NCNCannotConvertToValidURLSlugException(f"NCN '{value}' cannot be converted to an NCN-based URL slug") 74 return DocumentIdentifierSlug(ncn_based_uri_string)
Identifier schema describing a Neutral Citation Number.
https://www.iclr.co.uk/knowledge/case-law/neutral-citations/
Should this identifier type be considered for display as a 'human readable' identifier?
A multiplier used to adjust the relative ranking of this identifier when calculating preferred identifiers.
If present, a list of the names of document classes which can have this identifier.
If None, this identifier is valid for all document types.
54 @classmethod 55 def validate_identifier_value(cls, value: str) -> bool: 56 # Quick check to see if the NCN matches the expected pattern 57 if not bool(VALID_NCN_PATTERN.match(value)): 58 raise NCNDoesNotMatchExpectedPatternException(f"NCN '{value}' is not in the expected format") 59 60 # Can we convert this to a URL? neutral_url returns False if not. 61 # This functionally tests to see if the court exists, since only valid patterns (where we know how to match the court code) will convert 62 if not neutral_url(NeutralCitationString(value)): 63 raise NCNCannotConvertToValidURLSlugException(f"NCN '{value}' cannot be converted to an NCN-based URL slug") 64 65 return True
Check that any given identifier value is valid for this schema.
67 @classmethod 68 def compile_identifier_url_slug(cls, value: str) -> DocumentIdentifierSlug: 69 ncn_based_uri_string = neutral_url( 70 NeutralCitationString(value) 71 ) # TODO: At some point this should move out of utils and into this class. 72 if not ncn_based_uri_string: 73 raise NCNCannotConvertToValidURLSlugException(f"NCN '{value}' cannot be converted to an NCN-based URL slug") 74 return DocumentIdentifierSlug(ncn_based_uri_string)
Convert an identifier into a precompiled URL slug.
A base class for subclasses representing a concrete identifier.