lexichunk 0.9.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
lexichunk/__init__.py ADDED
@@ -0,0 +1,66 @@
1
+ """lexichunk — Legal document chunking SDK for RAG pipelines."""
2
+
3
+ import logging
4
+
5
+ from .chunker import ClassificationHook, LegalChunker
6
+ from .enrichment.clause_type import ClassificationResult
7
+ from .exceptions import (
8
+ ConfigurationError,
9
+ InputError,
10
+ LexichunkError,
11
+ ParsingError,
12
+ )
13
+ from .jurisdiction import (
14
+ register_jurisdiction,
15
+ registered_jurisdictions,
16
+ unregister_jurisdiction,
17
+ )
18
+ from .metrics import PipelineMetrics, StageMetric
19
+ from .offsets import OffsetMap, sanitize_with_map
20
+
21
+ # Library hygiene: don't emit "no handlers found" warnings for consumers who
22
+ # haven't configured logging. See docs/architecture.md "Logging and
23
+ # observability" for the DEBUG/WARNING policy this package follows.
24
+ logging.getLogger(__name__).addHandler(logging.NullHandler())
25
+ from .models import (
26
+ BatchError,
27
+ BatchResult,
28
+ ClauseType,
29
+ CrossReference,
30
+ DefinedTerm,
31
+ DocumentSection,
32
+ HierarchyNode,
33
+ Jurisdiction,
34
+ JurisdictionPatterns,
35
+ LegalChunk,
36
+ Section,
37
+ )
38
+
39
+ __version__ = "0.9.0"
40
+ __all__ = [
41
+ "LegalChunker",
42
+ "ClassificationHook",
43
+ "LegalChunk",
44
+ "Section",
45
+ "HierarchyNode",
46
+ "CrossReference",
47
+ "ClassificationResult",
48
+ "DefinedTerm",
49
+ "ClauseType",
50
+ "DocumentSection",
51
+ "Jurisdiction",
52
+ "JurisdictionPatterns",
53
+ "BatchResult",
54
+ "BatchError",
55
+ "PipelineMetrics",
56
+ "StageMetric",
57
+ "OffsetMap",
58
+ "sanitize_with_map",
59
+ "register_jurisdiction",
60
+ "unregister_jurisdiction",
61
+ "registered_jurisdictions",
62
+ "LexichunkError",
63
+ "ConfigurationError",
64
+ "ParsingError",
65
+ "InputError",
66
+ ]
lexichunk/_patterns.py ADDED
@@ -0,0 +1,66 @@
1
+ """Shared regex fragments for matching quoted defined-term names.
2
+
3
+ This module imports nothing from lexichunk, so both
4
+ :mod:`lexichunk.jurisdiction` and :mod:`lexichunk.parsers` can use it without
5
+ creating an import cycle.
6
+
7
+ Two defects motivated pulling these fragments out of the twenty-odd places
8
+ that previously spelled them inline:
9
+
10
+ * Every term-capture group used ``[A-Za-z\\s\\-]`` — letters, whitespace and
11
+ hyphen only. A document defining ``"R&D"``, ``"C++ Code"`` and
12
+ ``"Level 1 Support"`` yielded *zero* terms, and the same happened for
13
+ ``"Section 409A Plan"``, ``"Schedule 2 Services"`` and ``"Tier1"``. These
14
+ are ordinary term names in technology and commercial contracts, and the
15
+ loss was silent and total — not a mis-attachment, an absence.
16
+
17
+ * Nothing constrained what could precede an opening quote. In
18
+ ``1.1 "Client's Data" means the data supplied by the client.`` the regex
19
+ engine treated the apostrophe inside ``Client's`` as an opening single
20
+ quote, matched ``[a-z]`` = ``s``, then ``" Data"``, then the real closing
21
+ ``"`` — producing the bogus term ``"s Data"``. Possessive term names
22
+ ("Seller's Knowledge", "Purchaser's Group", "Guarantor's Obligations") are
23
+ standard M&A and commercial drafting.
24
+ """
25
+
26
+ from __future__ import annotations
27
+
28
+ #: Characters permitted *inside* a defined-term name, after the initial
29
+ #: letter. Digits and ``&``/``+`` are required by real term names; the two
30
+ #: apostrophe forms are required by possessive ones. Parentheses are
31
+ #: deliberately excluded so ``"Affiliate(s)"`` still reaches the dedicated
32
+ #: parenthesised-plural pattern rather than being captured verbatim.
33
+ TERM_CHARS = r"A-Za-z0-9\s\-&+'’"
34
+
35
+ #: A term name beginning with an upper-case letter.
36
+ TERM_UPPER = rf"[A-Z][{TERM_CHARS}]{{1,60}}"
37
+
38
+ #: A term name beginning with a lower-case letter.
39
+ TERM_LOWER = rf"[a-z][{TERM_CHARS}]{{1,60}}"
40
+
41
+ #: A term name beginning with a letter of either case.
42
+ TERM_ANY = rf"[A-Za-z][{TERM_CHARS}]{{1,60}}"
43
+
44
+ #: As :data:`TERM_ANY` but allowing a one-character name — used by the
45
+ #: parenthesised-plural pattern, where the ``(s)`` follows the stem.
46
+ TERM_ANY_SHORT = rf"[A-Za-z][{TERM_CHARS}]{{0,60}}"
47
+
48
+ #: A real opening quote is never preceded by a word character; a possessive
49
+ #: apostrophe always is. Guarding every opening-quote class with this
50
+ #: lookbehind is what stops ``Client's`` from opening a quote of its own.
51
+ #: It is a zero-width assertion, so it never shifts a capture group's number.
52
+ NOT_AFTER_WORD = r"(?<![A-Za-z0-9])"
53
+
54
+ #: Opening-quote character class, always used behind :data:`NOT_AFTER_WORD`.
55
+ OPEN_QUOTE = r"[\"'“‘]"
56
+
57
+ #: Closing-quote character class.
58
+ CLOSE_QUOTE = r"[\"'”’]"
59
+
60
+ #: Opening/closing pair for straight double + curly double quotes only.
61
+ OPEN_DOUBLE = r"[\"“]"
62
+ CLOSE_DOUBLE = r"[\"”]"
63
+
64
+ #: Opening/closing pair for straight single + curly single quotes only.
65
+ OPEN_SINGLE = r"['‘]"
66
+ CLOSE_SINGLE = r"['’]"