tulit 0.2.0__tar.gz → 0.2.2__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.0 → tulit-0.2.2}/PKG-INFO +1 -2
  2. {tulit-0.2.0 → tulit-0.2.2}/pyproject.toml +2 -2
  3. {tulit-0.2.0 → tulit-0.2.2}/tulit/parsers/xml/formex.py +67 -68
  4. {tulit-0.2.0 → tulit-0.2.2}/LICENSE +0 -0
  5. {tulit-0.2.0 → tulit-0.2.2}/README.md +0 -0
  6. {tulit-0.2.0 → tulit-0.2.2}/tulit/__init__.py +0 -0
  7. {tulit-0.2.0 → tulit-0.2.2}/tulit/client/__init__.py +0 -0
  8. {tulit-0.2.0 → tulit-0.2.2}/tulit/client/boe.py +0 -0
  9. {tulit-0.2.0 → tulit-0.2.2}/tulit/client/cellar.py +0 -0
  10. {tulit-0.2.0 → tulit-0.2.2}/tulit/client/client.py +0 -0
  11. {tulit-0.2.0 → tulit-0.2.2}/tulit/client/legifrance.py +0 -0
  12. {tulit-0.2.0 → tulit-0.2.2}/tulit/client/legilux.py +0 -0
  13. {tulit-0.2.0 → tulit-0.2.2}/tulit/client/normattiva.py +0 -0
  14. {tulit-0.2.0 → tulit-0.2.2}/tulit/client/veneto.py +0 -0
  15. {tulit-0.2.0 → tulit-0.2.2}/tulit/main.py +0 -0
  16. {tulit-0.2.0 → tulit-0.2.2}/tulit/parsers/__init__.py +0 -0
  17. {tulit-0.2.0 → tulit-0.2.2}/tulit/parsers/html/cellar.py +0 -0
  18. {tulit-0.2.0 → tulit-0.2.2}/tulit/parsers/html/veneto.py +0 -0
  19. {tulit-0.2.0 → tulit-0.2.2}/tulit/parsers/html/xhtml.py +0 -0
  20. {tulit-0.2.0 → tulit-0.2.2}/tulit/parsers/parser.py +0 -0
  21. {tulit-0.2.0 → tulit-0.2.2}/tulit/parsers/xml/akomantoso.py +0 -0
  22. {tulit-0.2.0 → tulit-0.2.2}/tulit/parsers/xml/assets/akomantoso30.xsd +0 -0
  23. {tulit-0.2.0 → tulit-0.2.2}/tulit/parsers/xml/assets/eli.owl +0 -0
  24. {tulit-0.2.0 → tulit-0.2.2}/tulit/parsers/xml/assets/formex4.xsd +0 -0
  25. {tulit-0.2.0 → tulit-0.2.2}/tulit/parsers/xml/assets/import/xml.xsd +0 -0
  26. {tulit-0.2.0 → tulit-0.2.2}/tulit/parsers/xml/assets/subdivisions.xml +0 -0
  27. {tulit-0.2.0 → tulit-0.2.2}/tulit/parsers/xml/assets/xml.xsd +0 -0
  28. {tulit-0.2.0 → tulit-0.2.2}/tulit/parsers/xml/xml.py +0 -0
  29. {tulit-0.2.0 → tulit-0.2.2}/tulit/rdf.py +0 -0
  30. {tulit-0.2.0 → tulit-0.2.2}/tulit/sparql.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: tulit
3
- Version: 0.2.0
3
+ Version: 0.2.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 pythonic data structures
5
5
  License: EUPL 1.2
6
6
  Author: AlessioNar
@@ -10,7 +10,6 @@ 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
14
13
  Requires-Dist: beautifulsoup4 (>=4.9.3,<5.0.0)
15
14
  Requires-Dist: chardet (>=5.2.0,<6.0.0)
16
15
  Requires-Dist: coverage (>=7.6.9,<8.0.0)
@@ -1,11 +1,11 @@
1
1
  [project]
2
2
  name = "tulit"
3
- version = "0.2.0"
3
+ version = "0.2.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 pythonic data structures"
5
5
 
6
6
  [tool.poetry]
7
7
  name = "tulit"
8
- version = "0.2.0"
8
+ version = "0.2.2"
9
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"
10
10
  authors = ["AlessioNar <alessio.nardin@gmail.com>"]
11
11
  license = "EUPL 1.2"
@@ -163,8 +163,8 @@ class Formex4Parser(XMLParser):
163
163
  extract_eId=extract_eId,
164
164
  get_headings=get_headings
165
165
  )
166
+
166
167
 
167
-
168
168
  def get_articles(self):
169
169
  """
170
170
  Extracts articles from the ENACTING.TERMS section. Articles are assumed to be contained within the
@@ -182,35 +182,56 @@ class Formex4Parser(XMLParser):
182
182
 
183
183
  self.articles = []
184
184
  if self.body is not None:
185
- for article in self.body.findall('.//ARTICLE'):
185
+ # The usage of xpath() method is to exclude nested ARTICLE elements
186
+ articles = self.body.xpath(".//ARTICLE[@IDENTIFIER][not(ancestor::ARTICLE)]")
187
+ for article in articles:
186
188
  article_eId = article.get("IDENTIFIER")
187
- article_eId = article_eId.lstrip('0')
189
+ article_eId = article_eId.lstrip('3')
188
190
  article_eId = f'art_{article_eId}'
191
+
189
192
  children = []
190
- amendments = []
191
-
192
- # Check if the article contains <QUOT.S> tag
193
+
194
+ # Check whether within the ARTICLE element there are
195
+ # QUOT.S elements, that mark the presence of amendments
193
196
  if article.findall('.//QUOT.S'):
194
- article, amendments = self._handle_amendments(article)
195
- print('Amendment article found!')
196
- print('\n')
197
-
198
- print('Amendments:', amendments)
199
- print('\n')
200
-
201
- # Extract text and metadata from all relevant elements within the article
202
- if article.findall('.//PARAG'):
203
- self._extract_elements(article, './/PARAG', children, amendments)
197
+ for alinea in article.xpath('.//ALINEA[not(ancestor::QUOT.S)]'):
198
+ children.append({
199
+ "eId": 0,
200
+ "text": self.clean_text(alinea),
201
+ "amendment": True
202
+ })
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
+
216
+
217
+ # Extract text and metadata from PARAG elements that are not descendants of QUOT.S elements (exclude amendments)
218
+ elif article.xpath('.//PARAG'):
219
+ self._extract_elements(article, './/PARAG', children)
204
220
  elif article.findall('.//ALINEA'):
205
221
  # If no PARAG elements, check for ALINEA elements
206
- alineas = article.findall('.//ALINEA')
222
+ alineas = article.xpath('.//ALINEA')
207
223
  for alinea in alineas:
208
- # if there are P elements within the ALINEA, extract them first, then extract LIST//ITEM elements, if they are still absent, extract the text from the ALINEA
209
- p_elements = alinea.findall('.//P')
210
- self._extract_elements(alinea, './/P', children, amendments)
211
- self._extract_elements(alinea, './/LIST//ITEM', children, amendments, start_index=len(p_elements))
212
- if not p_elements:
213
- self._extract_elements(alinea, '.', children, amendments)
224
+ p_elements = alinea.xpath('.//P')
225
+ if p_elements:
226
+ 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)
230
+ else:
231
+ self._extract_elements(alinea, '.', children)
232
+
233
+
234
+
214
235
 
215
236
  self.articles.append({
216
237
  "eId": article_eId,
@@ -223,8 +244,22 @@ class Formex4Parser(XMLParser):
223
244
  else:
224
245
  print('No enacting terms XML tag has been found')
225
246
  return []
226
-
227
- def _extract_elements(self, parent, xpath, children, amendments, start_index=0):
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
+
262
+ def _extract_elements(self, parent, xpath, children):
228
263
  """
229
264
  Helper method to extract text and metadata from elements.
230
265
 
@@ -236,55 +271,19 @@ class Formex4Parser(XMLParser):
236
271
  The XPath expression to locate the elements.
237
272
  children : list
238
273
  The list to append the extracted elements to.
239
- amendments : list
240
- List of amendments extracted from the article.
241
- start_index : int, optional
242
- The starting index for the elements (default is 0).
243
274
  """
244
275
  elements = parent.findall(xpath)
245
- amendment_index = 0
246
- for index, element in enumerate(elements, start=start_index):
247
- for sub_element in element.iter():
248
- if sub_element.tag == 'QUOT.START':
249
- sub_element.text = "‘"
250
- elif sub_element.tag == 'QUOT.END':
251
- sub_element.text = "’"
252
-
253
- text = "".join(element.itertext()).strip()
254
- text = re.sub(r'^\(\d+\)', '', text).strip()
255
- text = text.replace('\n', '').replace('\t', '').replace('\r', '') # remove newline and tab characters
256
- text = text.replace('\u00A0', ' ') # replace non-breaking spaces with regular spaces
257
- text = re.sub(' +', ' ', text) # replace multiple spaces with a single space
258
- text = re.sub(r'\s+([.,!?;:’])', r'\1', text) # replace spaces before punctuation with nothing
276
+ for index, element in enumerate(elements):
277
+
278
+ text = self.clean_text(element)
279
+
259
280
  if text is not None and text != '' and text != ';':
260
281
  child = {
261
282
  "eId": element.get("IDENTIFIER") or element.get("ID") or element.get("NO.P") or index,
262
- "text": text,
263
- "contains_amendment": amendment_index < len(amendments),
264
- "amendment": amendments[amendment_index] if amendment_index < len(amendments) else None
283
+ "text": text,
284
+ "amendment": False
265
285
  }
266
- children.append(child)
267
- amendment_index += 1
268
-
269
- def _handle_amendments(self, article):
270
- """
271
- Handles amendments made in the ACT using the <QUOT.S> tag.
272
-
273
- Parameters
274
- ----------
275
- article : lxml.etree._Element
276
- The article element to process.
277
- """
278
- amendments = []
279
- for quot_s in article.findall('.//QUOT.S'):
280
- amendment_text = " ".join(quot_s.itertext()).strip()
281
- # Process the amendment text as needed
282
- # For example, you could store it in a list or apply it to the article text
283
- amendments.append(amendment_text)
284
- # Remove the QUOT.S tags from the article using the self.remove_node method
285
- article = self.remove_node(article, './/QUOT.S')
286
- return article, amendments
287
-
286
+ children.append(child)
288
287
 
289
288
  def get_conclusions(self):
290
289
  """
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