tulit 0.2.2__tar.gz → 0.2.4__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.
- {tulit-0.2.2 → tulit-0.2.4}/PKG-INFO +3 -2
- {tulit-0.2.2 → tulit-0.2.4}/pyproject.toml +4 -4
- {tulit-0.2.2 → tulit-0.2.4}/tulit/parsers/xml/formex.py +33 -37
- {tulit-0.2.2 → tulit-0.2.4}/tulit/parsers/xml/xml.py +40 -24
- {tulit-0.2.2 → tulit-0.2.4}/LICENSE +0 -0
- {tulit-0.2.2 → tulit-0.2.4}/README.md +0 -0
- {tulit-0.2.2 → tulit-0.2.4}/tulit/__init__.py +0 -0
- {tulit-0.2.2 → tulit-0.2.4}/tulit/client/__init__.py +0 -0
- {tulit-0.2.2 → tulit-0.2.4}/tulit/client/boe.py +0 -0
- {tulit-0.2.2 → tulit-0.2.4}/tulit/client/cellar.py +0 -0
- {tulit-0.2.2 → tulit-0.2.4}/tulit/client/client.py +0 -0
- {tulit-0.2.2 → tulit-0.2.4}/tulit/client/legifrance.py +0 -0
- {tulit-0.2.2 → tulit-0.2.4}/tulit/client/legilux.py +0 -0
- {tulit-0.2.2 → tulit-0.2.4}/tulit/client/normattiva.py +0 -0
- {tulit-0.2.2 → tulit-0.2.4}/tulit/client/veneto.py +0 -0
- {tulit-0.2.2 → tulit-0.2.4}/tulit/main.py +0 -0
- {tulit-0.2.2 → tulit-0.2.4}/tulit/parsers/__init__.py +0 -0
- {tulit-0.2.2 → tulit-0.2.4}/tulit/parsers/html/cellar.py +0 -0
- {tulit-0.2.2 → tulit-0.2.4}/tulit/parsers/html/veneto.py +0 -0
- {tulit-0.2.2 → tulit-0.2.4}/tulit/parsers/html/xhtml.py +0 -0
- {tulit-0.2.2 → tulit-0.2.4}/tulit/parsers/parser.py +0 -0
- {tulit-0.2.2 → tulit-0.2.4}/tulit/parsers/xml/akomantoso.py +0 -0
- {tulit-0.2.2 → tulit-0.2.4}/tulit/parsers/xml/assets/akomantoso30.xsd +0 -0
- {tulit-0.2.2 → tulit-0.2.4}/tulit/parsers/xml/assets/eli.owl +0 -0
- {tulit-0.2.2 → tulit-0.2.4}/tulit/parsers/xml/assets/formex4.xsd +0 -0
- {tulit-0.2.2 → tulit-0.2.4}/tulit/parsers/xml/assets/import/xml.xsd +0 -0
- {tulit-0.2.2 → tulit-0.2.4}/tulit/parsers/xml/assets/subdivisions.xml +0 -0
- {tulit-0.2.2 → tulit-0.2.4}/tulit/parsers/xml/assets/xml.xsd +0 -0
- {tulit-0.2.2 → tulit-0.2.4}/tulit/rdf.py +0 -0
- {tulit-0.2.2 → tulit-0.2.4}/tulit/sparql.py +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: tulit
|
|
3
|
-
Version: 0.2.
|
|
4
|
-
Summary: TULIT - The Universal Legal Informatics Toolkit, is set of legal informatics utilities collected in a Python package that focuses on the retrieval of legal data and metadata from official sources in the EU, and their transformation in pythonic data
|
|
3
|
+
Version: 0.2.4
|
|
4
|
+
Summary: TULIT - The Universal Legal Informatics Toolkit, is set of legal informatics utilities collected in a Python package that focuses on the retrieval of legal data and metadata from official sources in the EU, and their transformation in legalJSON, a pythonic data structure for legal documents
|
|
5
5
|
License: EUPL 1.2
|
|
6
6
|
Author: AlessioNar
|
|
7
7
|
Author-email: alessio.nardin@gmail.com
|
|
@@ -10,6 +10,7 @@ Classifier: License :: Other/Proprietary License
|
|
|
10
10
|
Classifier: Operating System :: OS Independent
|
|
11
11
|
Classifier: Programming Language :: Python :: 3
|
|
12
12
|
Classifier: Programming Language :: Python :: 3.11
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
13
14
|
Requires-Dist: beautifulsoup4 (>=4.9.3,<5.0.0)
|
|
14
15
|
Requires-Dist: chardet (>=5.2.0,<6.0.0)
|
|
15
16
|
Requires-Dist: coverage (>=7.6.9,<8.0.0)
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "tulit"
|
|
3
|
-
version = "0.2.
|
|
4
|
-
description = "TULIT - The Universal Legal Informatics Toolkit, is set of legal informatics utilities collected in a Python package that focuses on the retrieval of legal data and metadata from official sources in the EU, and their transformation in pythonic data
|
|
3
|
+
version = "0.2.4"
|
|
4
|
+
description = "TULIT - The Universal Legal Informatics Toolkit, is set of legal informatics utilities collected in a Python package that focuses on the retrieval of legal data and metadata from official sources in the EU, and their transformation in legalJSON, a pythonic data structure for legal documents"
|
|
5
5
|
|
|
6
6
|
[tool.poetry]
|
|
7
7
|
name = "tulit"
|
|
8
|
-
version = "0.2.
|
|
9
|
-
description = "TULIT - The Universal Legal Informatics Toolkit, is set of legal informatics utilities collected in a Python package that focuses on the retrieval of legal data and metadata from official sources in the EU, and their transformation in pythonic data
|
|
8
|
+
version = "0.2.4"
|
|
9
|
+
description = "TULIT - The Universal Legal Informatics Toolkit, is set of legal informatics utilities collected in a Python package that focuses on the retrieval of legal data and metadata from official sources in the EU, and their transformation in legalJSON, a pythonic data structure for legal documents"
|
|
10
10
|
authors = ["AlessioNar <alessio.nardin@gmail.com>"]
|
|
11
11
|
license = "EUPL 1.2"
|
|
12
12
|
readme = "README.md"
|
|
@@ -191,48 +191,41 @@ class Formex4Parser(XMLParser):
|
|
|
191
191
|
|
|
192
192
|
children = []
|
|
193
193
|
|
|
194
|
+
index = 0
|
|
195
|
+
|
|
194
196
|
# Check whether within the ARTICLE element there are
|
|
195
197
|
# QUOT.S elements, that mark the presence of amendments
|
|
196
198
|
if article.findall('.//QUOT.S'):
|
|
197
199
|
for alinea in article.xpath('.//ALINEA[not(ancestor::QUOT.S)]'):
|
|
198
200
|
children.append({
|
|
199
|
-
"eId":
|
|
201
|
+
"eId": index,
|
|
200
202
|
"text": self.clean_text(alinea),
|
|
201
203
|
"amendment": True
|
|
202
204
|
})
|
|
203
|
-
|
|
204
|
-
#article.xpath('.//ALINEA')
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
# Treat amendments. First extract the text contained within the
|
|
208
|
-
# a P element that is outside of a LIST element
|
|
209
|
-
#for p in article.xpath('.//P[not(ancestor::LIST)]'):
|
|
210
|
-
# self._extract_elements(p, '.', children)
|
|
211
|
-
|
|
212
|
-
# Treat all the rest of the content of the ARTICLE element
|
|
213
|
-
# as a unique child
|
|
214
|
-
#children
|
|
215
|
-
|
|
205
|
+
|
|
216
206
|
|
|
217
|
-
# Extract text and metadata from PARAG elements
|
|
207
|
+
# Extract text and metadata from PARAG elements
|
|
208
|
+
# that are not descendants of QUOT.S elements (exclude amendments)
|
|
218
209
|
elif article.xpath('.//PARAG'):
|
|
219
210
|
self._extract_elements(article, './/PARAG', children)
|
|
220
211
|
elif article.findall('.//ALINEA'):
|
|
221
212
|
# If no PARAG elements, check for ALINEA elements
|
|
222
213
|
alineas = article.xpath('.//ALINEA')
|
|
223
214
|
for alinea in alineas:
|
|
215
|
+
|
|
224
216
|
p_elements = alinea.xpath('.//P')
|
|
225
|
-
if p_elements:
|
|
217
|
+
if p_elements:
|
|
226
218
|
for p in p_elements:
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
219
|
+
if not p.xpath('ancestor::ITEM'):
|
|
220
|
+
self._extract_elements(p, '.', children)
|
|
221
|
+
# Extract text and metadata from LIST/ITEM elements that are a direct child of ALINEA
|
|
222
|
+
# And exclude those that are descendants of other LIST/ITEM elements
|
|
223
|
+
for item in alinea.xpath('./LIST/ITEM'):
|
|
224
|
+
# Check if this is a top-level item (its parent LIST is a direct child of ALINEA)
|
|
225
|
+
self._extract_elements(item, '.', children)
|
|
230
226
|
else:
|
|
231
227
|
self._extract_elements(alinea, '.', children)
|
|
232
228
|
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
229
|
self.articles.append({
|
|
237
230
|
"eId": article_eId,
|
|
238
231
|
"num": article.findtext('.//TI.ART') or article.findtext('.//TI.ART//P'),
|
|
@@ -244,21 +237,7 @@ class Formex4Parser(XMLParser):
|
|
|
244
237
|
else:
|
|
245
238
|
print('No enacting terms XML tag has been found')
|
|
246
239
|
return []
|
|
247
|
-
|
|
248
|
-
def clean_text(self, element):
|
|
249
|
-
for sub_element in element.iter():
|
|
250
|
-
if sub_element.tag == 'QUOT.START':
|
|
251
|
-
sub_element.text = "‘"
|
|
252
|
-
elif sub_element.tag == 'QUOT.END':
|
|
253
|
-
sub_element.text = "’"
|
|
254
|
-
text = "".join(element.itertext()).strip()
|
|
255
|
-
text = re.sub(r'^\(\d+\)', '', text).strip()
|
|
256
|
-
text = text.replace('\n', '').replace('\t', '').replace('\r', '') # remove newline and tab characters
|
|
257
|
-
text = text.replace('\u00A0', ' ') # replace non-breaking spaces with regular spaces
|
|
258
|
-
text = re.sub(' +', ' ', text) # replace multiple spaces with a single space
|
|
259
|
-
text = re.sub(r'\s+([.,!?;:’])', r'\1', text) # replace spaces before punctuation with nothing
|
|
260
|
-
return text
|
|
261
|
-
|
|
240
|
+
|
|
262
241
|
def _extract_elements(self, parent, xpath, children):
|
|
263
242
|
"""
|
|
264
243
|
Helper method to extract text and metadata from elements.
|
|
@@ -318,6 +297,23 @@ class Formex4Parser(XMLParser):
|
|
|
318
297
|
return self.conclusions
|
|
319
298
|
|
|
320
299
|
|
|
300
|
+
def clean_text(self, element):
|
|
301
|
+
for sub_element in element.iter(): # Replace QUOT.START and QUOT.END elements with proper quotes
|
|
302
|
+
if sub_element.tag == 'QUOT.START':
|
|
303
|
+
sub_element.text = "‘"
|
|
304
|
+
elif sub_element.tag == 'QUOT.END':
|
|
305
|
+
sub_element.text = "’"
|
|
306
|
+
|
|
307
|
+
text = "".join(element.itertext()).strip() # Join text content of element and its descendants
|
|
308
|
+
text = re.sub(r'^\(\d+\)', '', text).strip() # Remove leading numbers in parentheses`
|
|
309
|
+
text = text.replace('\n', '').replace('\t', '').replace('\r', '') # remove newline and tab characters
|
|
310
|
+
text = text.replace('\u00A0', ' ') # replace non-breaking spaces with regular spaces
|
|
311
|
+
text = re.sub(' +', ' ', text) # replace multiple spaces with a single space
|
|
312
|
+
text = re.sub(r'\s+([.,!?;:’])', r'\1', text) # replace spaces before punctuation with nothing
|
|
313
|
+
|
|
314
|
+
return text
|
|
315
|
+
|
|
316
|
+
|
|
321
317
|
def parse(self, file):
|
|
322
318
|
"""
|
|
323
319
|
Parses a FORMEX XML document to extract its components, which are inherited from the XMLParser class.
|
|
@@ -3,6 +3,10 @@ import os
|
|
|
3
3
|
import re
|
|
4
4
|
from tulit.parsers.parser import Parser
|
|
5
5
|
|
|
6
|
+
import logging
|
|
7
|
+
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
|
|
8
|
+
logger = logging.getLogger(__name__)
|
|
9
|
+
|
|
6
10
|
class XMLParser(Parser):
|
|
7
11
|
"""
|
|
8
12
|
Base class for XML parsers.
|
|
@@ -437,67 +441,79 @@ class XMLParser(Parser):
|
|
|
437
441
|
if self.valid == True:
|
|
438
442
|
try:
|
|
439
443
|
self.get_root(file)
|
|
440
|
-
|
|
444
|
+
logger.info(f"Root element loaded successfully.")
|
|
441
445
|
except Exception as e:
|
|
442
|
-
|
|
446
|
+
logger.error(f"Error in get_root: {e}")
|
|
447
|
+
|
|
443
448
|
|
|
444
449
|
try:
|
|
445
450
|
self.get_preface()
|
|
446
|
-
|
|
451
|
+
logger.info(f"Preface element found. Preface: {self.preface}")
|
|
447
452
|
except Exception as e:
|
|
448
|
-
|
|
453
|
+
logger.error(f"Error in get_preface: {e}")
|
|
449
454
|
|
|
450
455
|
try:
|
|
451
456
|
self.get_preamble()
|
|
452
|
-
|
|
457
|
+
logger.info(f"Preamble element found.")
|
|
453
458
|
except Exception as e:
|
|
454
|
-
|
|
459
|
+
logger.error(f"Error in get_preamble: {e}")
|
|
455
460
|
try:
|
|
456
461
|
self.get_formula()
|
|
457
|
-
|
|
462
|
+
logger.info(f"Formula element found. Formula: {self.formula}")
|
|
458
463
|
except Exception as e:
|
|
459
|
-
|
|
464
|
+
logger.error(f"Error in get_formula: {e}")
|
|
460
465
|
try:
|
|
461
466
|
self.get_citations()
|
|
462
|
-
|
|
467
|
+
logger.info(f"Citations parsed successfully. Number of citations: {len(self.citations)}")
|
|
468
|
+
|
|
463
469
|
except Exception as e:
|
|
464
|
-
|
|
470
|
+
logger.error(f"Error in get_citations: {e}")
|
|
471
|
+
|
|
465
472
|
try:
|
|
466
473
|
self.get_recitals()
|
|
467
|
-
|
|
474
|
+
logger.info(f"Recitals parsed successfully. Number of recitals: {len(self.recitals)}")
|
|
475
|
+
|
|
468
476
|
except Exception as e:
|
|
469
|
-
|
|
477
|
+
logger.error(f"Error in get_recitals: {e}")
|
|
478
|
+
|
|
470
479
|
|
|
471
480
|
try:
|
|
472
481
|
self.get_preamble_final()
|
|
473
|
-
|
|
482
|
+
logger.info(f"Preamble final parsed successfully.")
|
|
483
|
+
|
|
474
484
|
except Exception as e:
|
|
475
|
-
|
|
485
|
+
logger.error(f"Error in get_preamble_final: {e}")
|
|
486
|
+
|
|
476
487
|
|
|
477
488
|
try:
|
|
478
489
|
self.get_body()
|
|
479
|
-
|
|
490
|
+
logger.info(f"Body element found.")
|
|
480
491
|
except Exception as e:
|
|
481
|
-
|
|
492
|
+
logger.error(f"Error in get_body: {e}")
|
|
493
|
+
|
|
482
494
|
try:
|
|
483
495
|
self.get_chapters()
|
|
484
|
-
|
|
496
|
+
logger.info(f"Chapters parsed successfully. Number of chapters: {len(self.chapters)}")
|
|
497
|
+
|
|
485
498
|
except Exception as e:
|
|
486
|
-
|
|
499
|
+
logger.error(f"Error in get_chapters: {e}")
|
|
500
|
+
|
|
487
501
|
try:
|
|
488
502
|
self.get_articles()
|
|
489
|
-
|
|
490
|
-
|
|
503
|
+
logger.info(f"Articles parsed successfully. Number of articles: {len(self.articles)}")
|
|
504
|
+
logger.info(f"Total number of children in articles: {sum([len(list(article)) for article in self.articles])}")
|
|
491
505
|
|
|
492
506
|
except Exception as e:
|
|
493
|
-
|
|
507
|
+
logger.error(f"Error in get_articles: {e}")
|
|
508
|
+
|
|
494
509
|
try:
|
|
495
510
|
self.get_conclusions()
|
|
496
|
-
|
|
511
|
+
logger.info(f"Conclusions parsed successfully.")
|
|
512
|
+
|
|
497
513
|
except Exception as e:
|
|
498
|
-
|
|
514
|
+
logger.error(f"Error in get_conclusions: {e}")
|
|
499
515
|
|
|
500
516
|
return self
|
|
501
517
|
|
|
502
518
|
except Exception as e:
|
|
503
|
-
|
|
519
|
+
logger.warn(f"Invalid {format} file: parsing may not work or work only partially: {e}")
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|