regexml 0.1.0__tar.gz

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.
@@ -0,0 +1,56 @@
1
+ # Byte-compiled / optimized / DLL files
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+
6
+ # C extensions
7
+ *.so
8
+
9
+ # Distribution / packaging
10
+ .Python
11
+ build/
12
+ develop-eggs/
13
+ dist/
14
+ downloads/
15
+ eggs/
16
+ .eggs/
17
+ lib/
18
+ lib64/
19
+ parts/
20
+ sdist/
21
+ var/
22
+ wheels/
23
+ share/python-wheels/
24
+ *.egg-info/
25
+ .installed.cfg
26
+ *.egg
27
+ MANIFEST
28
+
29
+ # Virtual environments
30
+ .env
31
+ .venv
32
+ env/
33
+ venv/
34
+ ENV/
35
+ env.bak/
36
+ venv.bak/
37
+
38
+ # Testing & Coverage
39
+ .tox/
40
+ .nox/
41
+ .coverage
42
+ .coverage.*
43
+ .cache
44
+ nosetests.xml
45
+ coverage.xml
46
+ *.cover
47
+ *.py,cover
48
+ .hypothesis/
49
+ .pytest_cache/
50
+
51
+ # IDE & OS
52
+ .vscode/
53
+ .idea/
54
+ *.swp
55
+ *.swo
56
+ .DS_Store
regexml-0.1.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Ishan
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
regexml-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,168 @@
1
+ Metadata-Version: 2.4
2
+ Name: regexml
3
+ Version: 0.1.0
4
+ Summary: A lightweight, fault-tolerant, text-first XML extraction library for Python.
5
+ Project-URL: Homepage, https://github.com/visitishan/regexml
6
+ Project-URL: Repository, https://github.com/visitishan/regexml
7
+ Project-URL: Issues, https://github.com/visitishan/regexml/issues
8
+ Author-email: Ishan <ishan@example.com>
9
+ License: MIT
10
+ License-File: LICENSE
11
+ Keywords: extractor,fault-tolerant,llm,parser,regex,scraping,xml
12
+ Classifier: Development Status :: 4 - Beta
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: License :: OSI Approved :: MIT License
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3.9
17
+ Classifier: Programming Language :: Python :: 3.10
18
+ Classifier: Programming Language :: Python :: 3.11
19
+ Classifier: Programming Language :: Python :: 3.12
20
+ Classifier: Programming Language :: Python :: 3.13
21
+ Classifier: Topic :: Text Processing :: Markup :: XML
22
+ Requires-Python: >=3.9
23
+ Provides-Extra: dev
24
+ Requires-Dist: pytest-cov>=4.0.0; extra == 'dev'
25
+ Requires-Dist: pytest>=7.0.0; extra == 'dev'
26
+ Description-Content-Type: text/markdown
27
+
28
+ # regexml 🚀
29
+
30
+ [![PyPI version](https://img.shields.io/pypi/v/regexml.svg)](https://pypi.org/project/regexml/)
31
+ [![Python Version](https://img.shields.io/badge/python-3.9+-blue.svg)](https://python.org)
32
+ [![License: MIT](https://img.shields.io/badge/License-MIT-green.svg)](LICENSE)
33
+
34
+ A lightweight, fault-tolerant, text-first XML extraction library for Python. Available on PyPI: **[pypi.org/project/regexml](https://pypi.org/project/regexml/)**.
35
+
36
+ Unlike traditional XML parsers (`xml.etree.ElementTree`, `lxml`) that enforce strict document validation and crash with `ParseError` on incomplete or malformed markup, **`regexml`** treats XML purely as plain text. It extracts values directly using regular expressions and resilient pattern matching.
37
+
38
+ ---
39
+
40
+ ## 🌟 Why `regexml`?
41
+
42
+ - **Fault-Tolerant & Resilient:** Doesn't crash on unescaped `&`, `<`, `>`, missing closing tags, or broken XML headers.
43
+ - **Perfect for LLM Outputs:** Cleanly extract tags like `<thought>`, `<answer>`, or `<code>` from AI responses.
44
+ - **Fluent Dot-Syntax Chaining:** Call `data.tagvalue("div").tagvalue("name")` seamlessly.
45
+ - **Balanced Outermost Tag Extraction:** Accurately captures outer tags with nested tags of the same name without premature cut-offs.
46
+ - **Truncated Stream Recovery:** If an XML stream cuts off prematurely (e.g. at line 1000 of 1200), it safely captures data up to EOF without failing.
47
+ - **Tag Inspector & Hierarchy:** Built-in `check_tags()` discovers all tags, reports unclosed/truncated tags, and renders visual ASCII trees.
48
+ - **Zero Heavy Dependencies:** Built 100% on Python standard library.
49
+
50
+ ---
51
+
52
+ ## 📦 Installation
53
+
54
+ ```bash
55
+ pip install regexml
56
+ ```
57
+
58
+ ---
59
+
60
+ ## ⚡ Quick Start
61
+
62
+ ### 1. Fluent Dot-Syntax (`XMLText`)
63
+
64
+ Wrap any string with `XMLText` to unlock dot-methods while retaining 100% string compatibility:
65
+
66
+ ```python
67
+ from regexml import XMLText
68
+
69
+ raw_data = """
70
+ <article id="101">
71
+ <title>Resilient XML Extraction</title>
72
+ <author>
73
+ <first_name>Ishan</first_name>
74
+ <last_name>Jain</last_name>
75
+ </author>
76
+ </article>
77
+ """
78
+
79
+ doc = XMLText(raw_data)
80
+
81
+ # Extract single tag value:
82
+ print(doc.tagvalue("title"))
83
+ # Output: Resilient XML Extraction
84
+
85
+ # Method Chaining:
86
+ print(doc.tagvalue("author").tagvalue("first_name"))
87
+ # Output: Ishan
88
+
89
+ # Path Shorthand:
90
+ print(doc.tagvalue("author/last_name"))
91
+ # Output: Jain
92
+ ```
93
+
94
+ ### 2. Functional API (Without Wrapping)
95
+
96
+ ```python
97
+ from regexml import tagvalue, tagvalues
98
+
99
+ data = "<user><name>Alice</name><name>Bob</name></user>"
100
+
101
+ print(tagvalue(data, "name")) # Alice
102
+ print(tagvalues(data, "name")) # ['Alice', 'Bob']
103
+ ```
104
+
105
+ ---
106
+
107
+ ## 🎯 Advanced Features
108
+
109
+ ### Balanced Nested Tags of the Same Name
110
+ Standard regex chops off at the first closing tag. `regexml` tracks depth counter to return the true balanced outermost tag:
111
+
112
+ ```python
113
+ xml = """
114
+ <div id="outer">
115
+ Hello
116
+ <div id="inner">World</div>
117
+ Welcome!
118
+ </div>
119
+ """
120
+ doc = XMLText(xml)
121
+ print(doc.tagvalue("div"))
122
+ # Output:
123
+ # Hello
124
+ # <div id="inner">World</div>
125
+ # Welcome!
126
+ ```
127
+
128
+ ### Truncated / Broken XML Recovery
129
+ If your XML was cut off mid-stream (e.g., from network drop or LLM token limit):
130
+
131
+ ```python
132
+ truncated_xml = "<user><id>123</id><bio>Software engineer who loves Python... [CUT OFF]"
133
+ doc = XMLText(truncated_xml)
134
+
135
+ bio = doc.tagvalue("bio")
136
+ print(bio) # "Software engineer who loves Python... [CUT OFF]"
137
+ print(bio.is_truncated) # True
138
+ ```
139
+
140
+ ### Tag Inspection & Broken Markup Detection (`check_tags`)
141
+
142
+ ```python
143
+ report = doc.check_tags()
144
+
145
+ # View all tags found:
146
+ print(report.tags) # ['user', 'id', 'bio']
147
+
148
+ # Pinpoint unclosed tags (truncated points):
149
+ print(report.unclosed_tags) # ['user', 'bio']
150
+
151
+ # Print terminal ASCII tree:
152
+ print(report.tree())
153
+ ```
154
+
155
+ **Output:**
156
+ ```text
157
+ └── user (unclosed)
158
+ ├── id
159
+ └── bio (unclosed)
160
+ ```
161
+
162
+ The tree instantly visualizes the markup hierarchy and flags unclosed tags, making it easy to pinpoint where the XML stream cut off.
163
+
164
+ ---
165
+
166
+ ## 📄 License
167
+
168
+ MIT License. Developed by Ishan.
@@ -0,0 +1,111 @@
1
+ # Project Progress & Roadmap: `regexml`
2
+
3
+ This document tracks the end-to-end development lifecycle of the **`regexml`** library. Use this checklist to monitor current progress, upcoming milestones, and completed features.
4
+
5
+ ---
6
+
7
+ ## 📊 Overall Progress Summary
8
+
9
+ | Metric | Status |
10
+ |---|---|
11
+ | **Current Phase** | Phase 6: Packaging, Documentation & Release |
12
+ | **Overall Completion** | 85% |
13
+ | **Target Python Version** | Python 3.9+ |
14
+ | **Dependencies** | Python Standard Library (`re`, `typing`, `dataclasses`) |
15
+
16
+ ---
17
+
18
+ ## 🗺️ Development Phases
19
+
20
+ ### Phase 1: Specification & Project Foundation ✅ (Completed)
21
+ - [x] Create Technical Specification document (`SPECIFICATION.md`)
22
+ - [x] Create Progress Tracking document (`PROGRESS.md`)
23
+ - [x] Initialize Git repository & `.gitignore`
24
+ - [x] Create GitHub repository: [visitishan/regexml](https://github.com/visitishan/regexml)
25
+ - [x] Initialize Python package layout (`src/regexml/`, `tests/`)
26
+ - [x] Create `pyproject.toml` with build metadata, dependencies, and linting tools
27
+ - [x] Create initial `README.md` with problem statement, quick start, and documentation
28
+ - [x] Create `LICENSE` (MIT)
29
+
30
+ ---
31
+
32
+ ### Phase 2: Core Regex Extraction Engine ✅ (Completed)
33
+ - [x] Implement data structures (`TagMatch`) in `models.py`
34
+ - [x] Implement core single-tag extractor `tagvalue(text, tag)` in `extractor.py`
35
+ - [x] Implement multi-occurrence extractor `tagvalues(text, tag)`
36
+ - [x] Implement `XMLText(str)` subclass wrapper for fluent dot-syntax (`my_text.tagvalue("div")`)
37
+ - [x] Implement Method Chaining support (`my_text.tagvalue("div").tagvalue("name").tagvalue("first_name")`)
38
+ - [x] Implement Safe Chaining (prevent `AttributeError` when intermediate tags are missing)
39
+ - [x] Implement Path Shorthand (`my_text.tagvalue("div/name/first_name")`)
40
+ - [x] Add basic parameters:
41
+ - [x] `include_tags: bool` (keep or strip surrounding `<tag>...</tag>`)
42
+ - [x] `strip_whitespace: bool`
43
+ - [x] `ignore_case: bool`
44
+ - [x] `multiline: bool` (DOTALL support)
45
+ - [x] Write unit tests for standard and clean XML snippets (`test_basic.py`)
46
+
47
+ ---
48
+
49
+ ### Phase 3: Fault-Tolerance & Attribute Handling ✅ (Completed)
50
+ - [x] Implement resilient attribute parser (`attributes.py`):
51
+ - [x] Support double-quoted, single-quoted, and unquoted values
52
+ - [x] Support boolean attributes (e.g. `<input disabled>`)
53
+ - [x] Filter extraction by matching attributes (`match_attributes={'id': 'main'}`)
54
+ - [x] Implement self-closing tag handling (`<tag ... />`)
55
+ - [x] Implement `tagmatch(text, tag)` returning `TagMatch` objects
56
+ - [x] Implement Truncated XML Graceful Recovery (`allow_unclosed=True`):
57
+ - [x] Extract content up to EOF or next peer tag when closing tag is missing
58
+ - [x] Attach `is_truncated = True` flag to matches
59
+ - [x] Implement CDATA handling (`<![CDATA[ ... ]]>`)
60
+ - [x] Write tests for dirty, truncated, and malformed XML (`test_malformed.py`)
61
+
62
+ ---
63
+
64
+ ### Phase 4: Advanced Scenarios (Nesting, Hierarchy & Inspection) ✅ (Completed)
65
+ - [x] Implement balanced depth-counter scanner for identical nested tags (`nested.py`)
66
+ - [x] Guarantee outermost opening tag matches corresponding balanced closing tag
67
+ - [x] Fallback graceful slice if XML is truncated mid-nest
68
+ - [x] Implement Tag Inspection & Hierarchy Engine (`check_tags()` in `inspector.py`):
69
+ - [x] Extract all distinct tags and their frequency counts
70
+ - [x] Identify unclosed / truncated tags via stack analysis
71
+ - [x] Build nested parent-child hierarchy map
72
+ - [x] Generate visual ASCII tree representation (`report.tree()`)
73
+ - [x] Handle XML namespaces:
74
+ - [x] Strict mode (`ns:tag`)
75
+ - [x] Relaxed mode (match tag name regardless of namespace prefix)
76
+ - [x] Implement batch extractor `extract_tags(text, tags=['a', 'b', 'c'])`
77
+ - [x] Implement `strip_inner_tags: bool` to recursively remove all inner child markup
78
+ - [x] Write tests for deeply nested, inspected, and namespaced tags (`test_nested.py`, `test_inspector.py`)
79
+
80
+ ---
81
+
82
+ ### Phase 5: LLM & Real-world Edge Cases ✅ (Completed)
83
+ - [x] Build test suite with real LLM prompt outputs (e.g., `<thought>`, `<code>`, markdown inside XML)
84
+ - [x] Handle unescaped characters (`<`, `>`, `&`, unclosed brackets in text)
85
+ - [x] Add comment stripping (`ignore_comments=True`)
86
+ - [x] All 23 unit tests across 5 test suites passing with 100% success rate
87
+
88
+ ---
89
+
90
+ ### Phase 6: Packaging, Documentation & Release ⏳ (In Progress)
91
+ - [x] Write full API reference in `README.md` with copy-pasteable examples
92
+ - [x] Setup `unittest` test suite with 23 passing test cases
93
+ - [ ] Verify package build with `python -m build`
94
+ - [ ] Add PyPI publishing workflow / instructions
95
+ - [ ] Final code review and version `0.1.0` tag
96
+
97
+ ---
98
+
99
+ ## 📝 Activity & Decision Log
100
+
101
+ | Date | Activity / Decision | Status |
102
+ |---|---|---|
103
+ | **2026-10-31** | Project inception: Decided on text-first, regex-based XML extraction to handle malformed XML & LLM outputs. | Done |
104
+ | **2026-10-31** | Created `SPECIFICATION.md` detailing API signatures, regex patterns, nesting strategy, and fault tolerance. | Done |
105
+ | **2026-10-31** | Created `PROGRESS.md` to track milestones across all 6 phases. | Done |
106
+ | **2026-11-01** | Added `XMLText(str)` subclass for fluent dot-syntax (`my_text.tagvalue("div")`) and finalized Outermost Balanced Depth Scanner algorithm in spec. | Done |
107
+ | **2026-11-01** | Designed Method Chaining (`.tagvalue().tagvalue()`), Safe Chaining (no AttributeError), and Path shorthand (`"div/name/first_name"`). | Done |
108
+ | **2026-11-01** | Designed Truncated XML Graceful Recovery (`allow_unclosed=True`, `is_truncated`) and Tag Inspection & Hierarchy Engine (`check_tags()` + `.tree()`). | Done |
109
+ | **2026-11-01** | Created public GitHub repository [visitishan/regexml](https://github.com/visitishan/regexml) and pushed initial commit. | Done |
110
+ | **2026-11-01** | Implemented core engine: `models.py`, `extractor.py`, `nested.py`, `inspector.py`, `attributes.py`, `utils.py`. | Done |
111
+ | **2026-11-01** | Added 23 unit tests across 5 test suites (`test_basic.py`, `test_nested.py`, `test_chaining.py`, `test_malformed.py`, `test_inspector.py`) — 100% passed. | Done |
@@ -0,0 +1,141 @@
1
+ # regexml 🚀
2
+
3
+ [![PyPI version](https://img.shields.io/pypi/v/regexml.svg)](https://pypi.org/project/regexml/)
4
+ [![Python Version](https://img.shields.io/badge/python-3.9+-blue.svg)](https://python.org)
5
+ [![License: MIT](https://img.shields.io/badge/License-MIT-green.svg)](LICENSE)
6
+
7
+ A lightweight, fault-tolerant, text-first XML extraction library for Python. Available on PyPI: **[pypi.org/project/regexml](https://pypi.org/project/regexml/)**.
8
+
9
+ Unlike traditional XML parsers (`xml.etree.ElementTree`, `lxml`) that enforce strict document validation and crash with `ParseError` on incomplete or malformed markup, **`regexml`** treats XML purely as plain text. It extracts values directly using regular expressions and resilient pattern matching.
10
+
11
+ ---
12
+
13
+ ## 🌟 Why `regexml`?
14
+
15
+ - **Fault-Tolerant & Resilient:** Doesn't crash on unescaped `&`, `<`, `>`, missing closing tags, or broken XML headers.
16
+ - **Perfect for LLM Outputs:** Cleanly extract tags like `<thought>`, `<answer>`, or `<code>` from AI responses.
17
+ - **Fluent Dot-Syntax Chaining:** Call `data.tagvalue("div").tagvalue("name")` seamlessly.
18
+ - **Balanced Outermost Tag Extraction:** Accurately captures outer tags with nested tags of the same name without premature cut-offs.
19
+ - **Truncated Stream Recovery:** If an XML stream cuts off prematurely (e.g. at line 1000 of 1200), it safely captures data up to EOF without failing.
20
+ - **Tag Inspector & Hierarchy:** Built-in `check_tags()` discovers all tags, reports unclosed/truncated tags, and renders visual ASCII trees.
21
+ - **Zero Heavy Dependencies:** Built 100% on Python standard library.
22
+
23
+ ---
24
+
25
+ ## 📦 Installation
26
+
27
+ ```bash
28
+ pip install regexml
29
+ ```
30
+
31
+ ---
32
+
33
+ ## ⚡ Quick Start
34
+
35
+ ### 1. Fluent Dot-Syntax (`XMLText`)
36
+
37
+ Wrap any string with `XMLText` to unlock dot-methods while retaining 100% string compatibility:
38
+
39
+ ```python
40
+ from regexml import XMLText
41
+
42
+ raw_data = """
43
+ <article id="101">
44
+ <title>Resilient XML Extraction</title>
45
+ <author>
46
+ <first_name>Ishan</first_name>
47
+ <last_name>Jain</last_name>
48
+ </author>
49
+ </article>
50
+ """
51
+
52
+ doc = XMLText(raw_data)
53
+
54
+ # Extract single tag value:
55
+ print(doc.tagvalue("title"))
56
+ # Output: Resilient XML Extraction
57
+
58
+ # Method Chaining:
59
+ print(doc.tagvalue("author").tagvalue("first_name"))
60
+ # Output: Ishan
61
+
62
+ # Path Shorthand:
63
+ print(doc.tagvalue("author/last_name"))
64
+ # Output: Jain
65
+ ```
66
+
67
+ ### 2. Functional API (Without Wrapping)
68
+
69
+ ```python
70
+ from regexml import tagvalue, tagvalues
71
+
72
+ data = "<user><name>Alice</name><name>Bob</name></user>"
73
+
74
+ print(tagvalue(data, "name")) # Alice
75
+ print(tagvalues(data, "name")) # ['Alice', 'Bob']
76
+ ```
77
+
78
+ ---
79
+
80
+ ## 🎯 Advanced Features
81
+
82
+ ### Balanced Nested Tags of the Same Name
83
+ Standard regex chops off at the first closing tag. `regexml` tracks depth counter to return the true balanced outermost tag:
84
+
85
+ ```python
86
+ xml = """
87
+ <div id="outer">
88
+ Hello
89
+ <div id="inner">World</div>
90
+ Welcome!
91
+ </div>
92
+ """
93
+ doc = XMLText(xml)
94
+ print(doc.tagvalue("div"))
95
+ # Output:
96
+ # Hello
97
+ # <div id="inner">World</div>
98
+ # Welcome!
99
+ ```
100
+
101
+ ### Truncated / Broken XML Recovery
102
+ If your XML was cut off mid-stream (e.g., from network drop or LLM token limit):
103
+
104
+ ```python
105
+ truncated_xml = "<user><id>123</id><bio>Software engineer who loves Python... [CUT OFF]"
106
+ doc = XMLText(truncated_xml)
107
+
108
+ bio = doc.tagvalue("bio")
109
+ print(bio) # "Software engineer who loves Python... [CUT OFF]"
110
+ print(bio.is_truncated) # True
111
+ ```
112
+
113
+ ### Tag Inspection & Broken Markup Detection (`check_tags`)
114
+
115
+ ```python
116
+ report = doc.check_tags()
117
+
118
+ # View all tags found:
119
+ print(report.tags) # ['user', 'id', 'bio']
120
+
121
+ # Pinpoint unclosed tags (truncated points):
122
+ print(report.unclosed_tags) # ['user', 'bio']
123
+
124
+ # Print terminal ASCII tree:
125
+ print(report.tree())
126
+ ```
127
+
128
+ **Output:**
129
+ ```text
130
+ └── user (unclosed)
131
+ ├── id
132
+ └── bio (unclosed)
133
+ ```
134
+
135
+ The tree instantly visualizes the markup hierarchy and flags unclosed tags, making it easy to pinpoint where the XML stream cut off.
136
+
137
+ ---
138
+
139
+ ## 📄 License
140
+
141
+ MIT License. Developed by Ishan.