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.
Files changed (30) hide show
  1. {tulit-0.2.2 → tulit-0.2.4}/PKG-INFO +3 -2
  2. {tulit-0.2.2 → tulit-0.2.4}/pyproject.toml +4 -4
  3. {tulit-0.2.2 → tulit-0.2.4}/tulit/parsers/xml/formex.py +33 -37
  4. {tulit-0.2.2 → tulit-0.2.4}/tulit/parsers/xml/xml.py +40 -24
  5. {tulit-0.2.2 → tulit-0.2.4}/LICENSE +0 -0
  6. {tulit-0.2.2 → tulit-0.2.4}/README.md +0 -0
  7. {tulit-0.2.2 → tulit-0.2.4}/tulit/__init__.py +0 -0
  8. {tulit-0.2.2 → tulit-0.2.4}/tulit/client/__init__.py +0 -0
  9. {tulit-0.2.2 → tulit-0.2.4}/tulit/client/boe.py +0 -0
  10. {tulit-0.2.2 → tulit-0.2.4}/tulit/client/cellar.py +0 -0
  11. {tulit-0.2.2 → tulit-0.2.4}/tulit/client/client.py +0 -0
  12. {tulit-0.2.2 → tulit-0.2.4}/tulit/client/legifrance.py +0 -0
  13. {tulit-0.2.2 → tulit-0.2.4}/tulit/client/legilux.py +0 -0
  14. {tulit-0.2.2 → tulit-0.2.4}/tulit/client/normattiva.py +0 -0
  15. {tulit-0.2.2 → tulit-0.2.4}/tulit/client/veneto.py +0 -0
  16. {tulit-0.2.2 → tulit-0.2.4}/tulit/main.py +0 -0
  17. {tulit-0.2.2 → tulit-0.2.4}/tulit/parsers/__init__.py +0 -0
  18. {tulit-0.2.2 → tulit-0.2.4}/tulit/parsers/html/cellar.py +0 -0
  19. {tulit-0.2.2 → tulit-0.2.4}/tulit/parsers/html/veneto.py +0 -0
  20. {tulit-0.2.2 → tulit-0.2.4}/tulit/parsers/html/xhtml.py +0 -0
  21. {tulit-0.2.2 → tulit-0.2.4}/tulit/parsers/parser.py +0 -0
  22. {tulit-0.2.2 → tulit-0.2.4}/tulit/parsers/xml/akomantoso.py +0 -0
  23. {tulit-0.2.2 → tulit-0.2.4}/tulit/parsers/xml/assets/akomantoso30.xsd +0 -0
  24. {tulit-0.2.2 → tulit-0.2.4}/tulit/parsers/xml/assets/eli.owl +0 -0
  25. {tulit-0.2.2 → tulit-0.2.4}/tulit/parsers/xml/assets/formex4.xsd +0 -0
  26. {tulit-0.2.2 → tulit-0.2.4}/tulit/parsers/xml/assets/import/xml.xsd +0 -0
  27. {tulit-0.2.2 → tulit-0.2.4}/tulit/parsers/xml/assets/subdivisions.xml +0 -0
  28. {tulit-0.2.2 → tulit-0.2.4}/tulit/parsers/xml/assets/xml.xsd +0 -0
  29. {tulit-0.2.2 → tulit-0.2.4}/tulit/rdf.py +0 -0
  30. {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.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 structures
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.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 structures"
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.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 structures"
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": 0,
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 that are not descendants of QUOT.S elements (exclude amendments)
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
- self._extract_elements(p, '.', children)
228
- for item in alinea.findall('.//LIST//ITEM'):
229
- self._extract_elements(item, '.', children)
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
- print("Root element loaded successfully.")
444
+ logger.info(f"Root element loaded successfully.")
441
445
  except Exception as e:
442
- print(f"Error in get_root: {e}")
446
+ logger.error(f"Error in get_root: {e}")
447
+
443
448
 
444
449
  try:
445
450
  self.get_preface()
446
- print(f"Preface parsed successfully. Preface: {self.preface}")
451
+ logger.info(f"Preface element found. Preface: {self.preface}")
447
452
  except Exception as e:
448
- print(f"Error in get_preface: {e}")
453
+ logger.error(f"Error in get_preface: {e}")
449
454
 
450
455
  try:
451
456
  self.get_preamble()
452
- print(f"Preamble element found.")
457
+ logger.info(f"Preamble element found.")
453
458
  except Exception as e:
454
- print(f"Error in get_preamble: {e}")
459
+ logger.error(f"Error in get_preamble: {e}")
455
460
  try:
456
461
  self.get_formula()
457
- print(f"Formula parsed successfully.")
462
+ logger.info(f"Formula element found. Formula: {self.formula}")
458
463
  except Exception as e:
459
- print(f"Error in get_formula: {e}")
464
+ logger.error(f"Error in get_formula: {e}")
460
465
  try:
461
466
  self.get_citations()
462
- print(f"Citations parsed successfully. Number of citations: {len(self.citations)}")
467
+ logger.info(f"Citations parsed successfully. Number of citations: {len(self.citations)}")
468
+
463
469
  except Exception as e:
464
- print(f"Error in get_citations: {e}")
470
+ logger.error(f"Error in get_citations: {e}")
471
+
465
472
  try:
466
473
  self.get_recitals()
467
- print(f"Recitals parsed successfully. Number of recitals: {len(self.recitals)}")
474
+ logger.info(f"Recitals parsed successfully. Number of recitals: {len(self.recitals)}")
475
+
468
476
  except Exception as e:
469
- print(f"Error in get_recitals: {e}")
477
+ logger.error(f"Error in get_recitals: {e}")
478
+
470
479
 
471
480
  try:
472
481
  self.get_preamble_final()
473
- print(f"Preamble final parsed successfully.")
482
+ logger.info(f"Preamble final parsed successfully.")
483
+
474
484
  except Exception as e:
475
- print(f"Error in get_preamble_final: {e}")
485
+ logger.error(f"Error in get_preamble_final: {e}")
486
+
476
487
 
477
488
  try:
478
489
  self.get_body()
479
- print("Body element found.")
490
+ logger.info(f"Body element found.")
480
491
  except Exception as e:
481
- print(f"Error in get_body: {e}")
492
+ logger.error(f"Error in get_body: {e}")
493
+
482
494
  try:
483
495
  self.get_chapters()
484
- print(f"Chapters parsed successfully. Number of chapters: {len(self.chapters)}")
496
+ logger.info(f"Chapters parsed successfully. Number of chapters: {len(self.chapters)}")
497
+
485
498
  except Exception as e:
486
- print(f"Error in get_chapters: {e}")
499
+ logger.error(f"Error in get_chapters: {e}")
500
+
487
501
  try:
488
502
  self.get_articles()
489
- print(f"Articles parsed successfully. Number of articles: {len(self.articles)}")
490
- print(f"Total number of children in articles: {sum([len(list(article)) for article in self.articles])}")
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
- print(f"Error in get_articles: {e}")
507
+ logger.error(f"Error in get_articles: {e}")
508
+
494
509
  try:
495
510
  self.get_conclusions()
496
- print(f"Conclusions parsed successfully. ")
511
+ logger.info(f"Conclusions parsed successfully.")
512
+
497
513
  except Exception as e:
498
- print(f"Error in get_conclusions: {e}")
514
+ logger.error(f"Error in get_conclusions: {e}")
499
515
 
500
516
  return self
501
517
 
502
518
  except Exception as e:
503
- print(f'Invalid {self.format} file: parsing may not work or work only partially: {e}')
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