otlmow-template 1.2__py3-none-any.whl → 1.4__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.
@@ -1,11 +1,12 @@
1
+ import asyncio
2
+ import concurrent
1
3
  import contextlib
2
4
  import csv
3
5
  import logging
4
6
  import os
5
- import shutil
6
- import tempfile
7
7
  from asyncio import sleep
8
8
  from collections import defaultdict
9
+ from concurrent.futures import ThreadPoolExecutor, as_completed, ALL_COMPLETED
9
10
  from pathlib import Path
10
11
 
11
12
  from openpyxl.reader.excel import load_workbook
@@ -16,13 +17,15 @@ from openpyxl.worksheet.datavalidation import DataValidation
16
17
  from openpyxl.worksheet.dimensions import DimensionHolder, ColumnDimension
17
18
  from openpyxl.worksheet.worksheet import Worksheet
18
19
  from otlmow_converter.DotnotationHelper import DotnotationHelper
20
+ from otlmow_converter.Exceptions.UnknownExcelError import UnknownExcelError
19
21
  from otlmow_converter.OtlmowConverter import OtlmowConverter
20
22
  from otlmow_model.OtlmowModel.BaseClasses.BooleanField import BooleanField
21
23
  from otlmow_model.OtlmowModel.BaseClasses.KeuzelijstField import KeuzelijstField
22
24
  from otlmow_model.OtlmowModel.BaseClasses.OTLObject import dynamic_create_instance_from_uri, OTLObject, \
23
- get_attribute_by_name
25
+ get_attribute_by_name, dynamic_create_type_from_uri
26
+ from otlmow_model.OtlmowModel.Helpers.GenericHelper import get_ns_and_name_from_uri
27
+ from otlmow_model.OtlmowModel.Helpers.RelationCreator import create_betrokkenerelation, create_relation
24
28
  from otlmow_model.OtlmowModel.Helpers.generated_lists import get_hardcoded_relation_dict
25
- from otlmow_modelbuilder.HelperFunctions import get_ns_and_name_from_uri
26
29
  from otlmow_modelbuilder.OSLOCollector import OSLOCollector
27
30
  from otlmow_modelbuilder.SQLDataClasses.OSLOClass import OSLOClass
28
31
 
@@ -167,6 +170,34 @@ class SubsetTemplateCreator:
167
170
  split_per_type=split_per_type, file_path=template_file_path, dummy_data_rows=dummy_data_rows,
168
171
  instances=objects, add_deprecated=add_deprecated, add_attribute_info=add_attribute_info)
169
172
 
173
+
174
+ @classmethod
175
+ def create_x_objects(cls, oslo_class, add_geometry, collector, filter_attributes_by_subset, model_directory,
176
+ amount_objects_to_create):
177
+ if oslo_class.objectUri in cls.relation_dict:
178
+ return []
179
+
180
+ otl_objects = []
181
+ for _ in range(amount_objects_to_create):
182
+ otl_object = cls.generate_object_from_oslo_class(
183
+ oslo_class=oslo_class, add_geometry=add_geometry, collector=collector,
184
+ filter_attributes_by_subset=filter_attributes_by_subset, model_directory=model_directory)
185
+ if otl_object is not None:
186
+ otl_objects.append(otl_object)
187
+ return otl_objects
188
+
189
+ @classmethod
190
+ def get_number_of_cpus(cls) -> int:
191
+ import multiprocessing
192
+ cpu_count = multiprocessing.cpu_count()
193
+ if cpu_count is None or cpu_count == 0:
194
+ import os
195
+ cpu_count = os.cpu_count()
196
+ if cpu_count is None or cpu_count == 0:
197
+ cpu_count = 8
198
+ return cpu_count
199
+
200
+
170
201
  @classmethod
171
202
  def generate_objects_for_template(
172
203
  cls, subset_path: Path, class_uris_filter: [str], filter_attributes_by_subset: bool,
@@ -177,31 +208,60 @@ class SubsetTemplateCreator:
177
208
  """
178
209
  collector = cls._load_collector_from_subset_path(subset_path=subset_path)
179
210
  filtered_class_list = cls.filters_classes_by_subset(collector=collector, class_uris_filter=class_uris_filter)
180
- relation_dict = get_hardcoded_relation_dict(model_directory=model_directory)
211
+ cls.relation_dict = get_hardcoded_relation_dict(model_directory=model_directory)
181
212
 
182
213
  amount_objects_to_create = max(1, dummy_data_rows)
183
214
  otl_objects = []
184
215
 
185
216
  while True:
186
- for oslo_class in [cl for cl in filtered_class_list if cl.abstract == 0]:
187
- if ignore_relations and oslo_class.objectUri in relation_dict:
188
- continue
217
+ with ThreadPoolExecutor(max_workers=cls.get_number_of_cpus()) as executor:
218
+ futures = [
219
+ executor.submit(cls.create_x_objects, oslo_class, add_geometry, collector,
220
+ filter_attributes_by_subset, model_directory, amount_objects_to_create)
221
+ for oslo_class in [cl for cl in filtered_class_list if cl.abstract == 0]
222
+ ]
223
+ while futures:
224
+ done, not_done = concurrent.futures.wait(futures, return_when=ALL_COMPLETED, timeout=60)
225
+ for future in as_completed(done):
226
+ otl_objects.extend(future.result())
227
+ futures = not_done
228
+ print(f'when using multiprocessing: {len(done)} done, {len(not_done)} not done')
229
+ if len(not_done) > 0:
230
+ print('restarting the loop with the not done ones')
189
231
 
190
- for _ in range(amount_objects_to_create):
191
- otl_object = cls.generate_object_from_oslo_class(
192
- oslo_class=oslo_class, add_geometry=add_geometry, collector=collector,
193
- filter_attributes_by_subset=filter_attributes_by_subset, model_directory=model_directory)
194
- if otl_object is not None:
195
- otl_objects.append(otl_object)
196
232
  created = len(otl_objects)
197
- unique_ids = len({obj.assetId.identificator if hasattr(obj, 'assetId') else obj.agentId.identificator
233
+ unique_ids = len({obj.assetId.identificator if obj.typeURI != 'http://purl.org/dc/terms/Agent' else obj.agentId.identificator
198
234
  for obj in otl_objects})
199
235
  if created == unique_ids:
200
236
  break
201
237
  otl_objects = []
202
238
 
239
+ if not ignore_relations:
240
+ non_relations_class_uris = [cl.objectUri for cl in filtered_class_list
241
+ if cl.abstract == 0 and cl.objectUri not in cls.relation_dict]
242
+ cls.append_relations_to_objects(otl_objects=otl_objects, collector=collector,
243
+ class_uris_filter=non_relations_class_uris, model_directory=model_directory)
244
+
203
245
  return otl_objects
204
246
 
247
+ @classmethod
248
+ async def create_x_objects_async(cls, oslo_class, add_geometry, collector, filter_attributes_by_subset,
249
+ model_directory,
250
+ amount_objects_to_create):
251
+ if oslo_class.objectUri in cls.relation_dict:
252
+ return []
253
+
254
+ otl_objects = []
255
+ for _ in range(amount_objects_to_create):
256
+ await sleep(0)
257
+ otl_object = cls.generate_object_from_oslo_class(
258
+ oslo_class=oslo_class, add_geometry=add_geometry, collector=collector,
259
+ filter_attributes_by_subset=filter_attributes_by_subset, model_directory=model_directory)
260
+ if otl_object is not None:
261
+ otl_objects.append(otl_object)
262
+ return otl_objects
263
+
264
+
205
265
  @classmethod
206
266
  async def generate_objects_for_template_async(
207
267
  cls, subset_path: Path, class_uris_filter: [str], filter_attributes_by_subset: bool,
@@ -215,23 +275,33 @@ class SubsetTemplateCreator:
215
275
  await sleep(0)
216
276
  filtered_class_list = cls.filters_classes_by_subset(collector=collector, class_uris_filter=class_uris_filter)
217
277
  await sleep(0)
218
- relation_dict = get_hardcoded_relation_dict(model_directory=model_directory)
278
+ cls.relation_dict = get_hardcoded_relation_dict(model_directory=model_directory)
219
279
 
220
280
  amount_objects_to_create = max(1, dummy_data_rows)
221
281
  otl_objects = []
222
282
 
223
- for oslo_class in [cl for cl in filtered_class_list if cl.abstract == 0]:
224
- await sleep(0)
225
- if ignore_relations and oslo_class.objectUri in relation_dict:
226
- continue
283
+ while True:
284
+ tasks = [
285
+ cls.create_x_objects_async(oslo_class, add_geometry, collector,
286
+ filter_attributes_by_subset, model_directory, amount_objects_to_create)
287
+ for oslo_class in [cl for cl in filtered_class_list if cl.abstract == 0]
288
+ ]
289
+ results = await asyncio.gather(*tasks)
290
+ otl_objects.extend([item for sublist in results for item in sublist])
227
291
 
228
- for _ in range(amount_objects_to_create):
229
- otl_object = cls.generate_object_from_oslo_class(
230
- oslo_class=oslo_class, add_geometry=add_geometry, collector=collector,
231
- filter_attributes_by_subset=filter_attributes_by_subset, model_directory=model_directory)
232
- await sleep(0)
233
- if otl_object is not None:
234
- otl_objects.append(otl_object)
292
+ created = len(otl_objects)
293
+ unique_ids = len({
294
+ obj.assetId.identificator if obj.typeURI != 'http://purl.org/dc/terms/Agent' else obj.agentId.identificator
295
+ for obj in otl_objects})
296
+ if created == unique_ids:
297
+ break
298
+ otl_objects = []
299
+
300
+ if not ignore_relations:
301
+ non_relations_class_uris = [cl.objectUri for cl in filtered_class_list
302
+ if cl.abstract == 0 and cl.objectUri not in cls.relation_dict]
303
+ cls.append_relations_to_objects(otl_objects=otl_objects, collector=collector,
304
+ class_uris_filter=non_relations_class_uris, model_directory=model_directory)
235
305
 
236
306
  return otl_objects
237
307
 
@@ -249,15 +319,23 @@ class SubsetTemplateCreator:
249
319
  if filter_attributes_by_subset:
250
320
  for attribute_object in collector.find_attributes_by_class(oslo_class):
251
321
  attr = get_attribute_by_name(instance, attribute_object.name)
252
- if attr is not None:
253
- attr.fill_with_dummy_data()
254
- else:
322
+ if attr is None:
255
323
  logging.warning(f'Attribute {attribute_object.name} not found in class {oslo_class.objectUri}')
324
+ elif attr.naam == 'isActief':
325
+ attr.set_waarde(True)
326
+ else:
327
+ attr.fill_with_dummy_data()
256
328
  else:
257
329
  for attr in instance:
258
- if attr.naam != 'geometry':
330
+ if attr.naam == 'isActief':
331
+ attr.set_waarde(True)
332
+ elif attr.naam != 'geometry':
259
333
  attr.fill_with_dummy_data()
334
+
260
335
  with contextlib.suppress(AttributeError):
336
+ assetId_attr = get_attribute_by_name(instance, 'assetId')
337
+ if assetId_attr is not None:
338
+ assetId_attr.fill_with_dummy_data()
261
339
  if add_geometry:
262
340
  geo_attr = get_attribute_by_name(instance, 'geometry')
263
341
  if geo_attr is not None:
@@ -304,7 +382,10 @@ class SubsetTemplateCreator:
304
382
  if split_per_type:
305
383
  for type_uri, typed_instances in classes_dict.items():
306
384
  ns, name = get_ns_and_name_from_uri(type_uri)
307
- class_file_path = file_path.parent / f'{file_path.stem}_{ns}_{name}.csv'
385
+ ns_name = f'{ns}_{name}'
386
+ if name == 'Agent':
387
+ ns_name = 'Agent'
388
+ class_file_path = file_path.parent / f'{file_path.stem}_{ns_name}.csv'
308
389
  cls.alter_csv_file(add_attribute_info=add_attribute_info, add_deprecated=add_deprecated,
309
390
  dummy_data_rows=dummy_data_rows, instances=typed_instances, file_path=class_file_path)
310
391
  else:
@@ -319,7 +400,10 @@ class SubsetTemplateCreator:
319
400
  for type_uri, typed_instances in classes_dict.items():
320
401
  await sleep(0)
321
402
  ns, name = get_ns_and_name_from_uri(type_uri)
322
- class_file_path = file_path.parent / f'{file_path.stem}_{ns}_{name}.csv'
403
+ ns_name = f'{ns}_{name}'
404
+ if name == 'Agent':
405
+ ns_name = 'Agent'
406
+ class_file_path = file_path.parent / f'{file_path.stem}_{ns_name}.csv'
323
407
  cls.alter_csv_file(add_attribute_info=add_attribute_info,
324
408
  dummy_data_rows=dummy_data_rows, instances=typed_instances, add_deprecated=add_deprecated,
325
409
  file_path=class_file_path)
@@ -354,7 +438,14 @@ class SubsetTemplateCreator:
354
438
  deprecated_attributes_row.append('')
355
439
  continue
356
440
 
357
- attribute = DotnotationHelper.get_attribute_by_dotnotation(instance, header)
441
+ try:
442
+ attribute = DotnotationHelper.get_attribute_by_dotnotation(instance, header)
443
+ except AttributeError:
444
+ if add_attribute_info:
445
+ collected_attribute_info_row.append('')
446
+ if add_deprecated:
447
+ deprecated_attributes_row.append('')
448
+ continue
358
449
 
359
450
  if add_attribute_info:
360
451
  collected_attribute_info_row.append(attribute.definition)
@@ -362,7 +453,7 @@ class SubsetTemplateCreator:
362
453
  if add_deprecated:
363
454
  deprecated_attributes_row.append('DEPRECATED' if attribute.deprecated_version else '')
364
455
 
365
- with open(file_path, 'w') as file:
456
+ with open(file_path, 'w', newline='', encoding='utf-8') as file:
366
457
  csv_writer = csv.writer(file, delimiter=';', quotechar=quote_char, quoting=csv.QUOTE_MINIMAL)
367
458
  if add_attribute_info:
368
459
  csv_writer.writerow(collected_attribute_info_row)
@@ -397,7 +488,11 @@ class SubsetTemplateCreator:
397
488
  instances: [OTLObject], sheet: Worksheet, add_deprecated: bool, workbook: Workbook,
398
489
  dummy_data_rows: int):
399
490
  type_uri = cls.get_uri_from_sheet_name(sheet.title)
400
- instance = next(x for x in instances if x.typeURI == type_uri)
491
+ instance = next((x for x in instances if x.typeURI == type_uri), None)
492
+ if instance is None:
493
+ instance = next((x for x in instances if x.typeURI.startswith(type_uri)), None)
494
+ if instance is None:
495
+ raise UnknownExcelError(f'When creating a template, no instance could be created for {type_uri}')
401
496
 
402
497
  boolean_validation = DataValidation(type="list", formula1='"TRUE,FALSE,"', allow_blank=True)
403
498
  sheet.add_data_validation(boolean_validation)
@@ -461,13 +556,14 @@ class SubsetTemplateCreator:
461
556
  cell.fill = PatternFill(start_color="FF7276", end_color="FF7276", fill_type="solid")
462
557
 
463
558
  @classmethod
464
- def add_attribute_info_to_sheet(cls, collected_attribute_info, sheet):
559
+ def add_attribute_info_to_sheet(cls, collected_attribute_info: list[str], sheet: Worksheet):
465
560
  sheet.insert_rows(idx=1)
561
+ fill = PatternFill(start_color="808080", fill_type="solid")
562
+ alignment = Alignment(wrapText=True, vertical='top')
466
563
  for index, attr_info in enumerate(collected_attribute_info, start=1):
467
- cell = sheet.cell(row=1, column=index)
468
- cell.value = attr_info
469
- cell.alignment = Alignment(wrapText=True, vertical='top')
470
- cell.fill = PatternFill(start_color="808080", end_color="808080", fill_type="solid")
564
+ cell = sheet.cell(row=1, column=index, value=attr_info)
565
+ cell.alignment = alignment
566
+ cell.fill = fill
471
567
 
472
568
  @classmethod
473
569
  def generate_choice_list_in_excel(cls, attribute, choice_list_dict, column, row_nr, sheet: Worksheet,
@@ -610,3 +706,28 @@ class SubsetTemplateCreator:
610
706
  raise ValueError('Sheet title does not contain a #')
611
707
  class_ns, class_name = title.split('#', maxsplit=1)
612
708
  return short_to_long_ns.get(class_ns, class_ns) + class_name
709
+
710
+ @classmethod
711
+ def append_relations_to_objects(cls, otl_objects: [OTLObject], collector: OSLOCollector, class_uris_filter: [str],
712
+ model_directory: Path):
713
+ class_dict = defaultdict(list)
714
+ for instance in otl_objects:
715
+ class_dict[instance.typeURI].append(instance)
716
+
717
+ for class_uri in class_uris_filter:
718
+ for relation in collector.find_all_concrete_relations(objectUri=class_uri):
719
+ if class_uri != relation.bron_uri:
720
+ continue
721
+ for i, bron_instance in enumerate(class_dict[relation.bron_uri]):
722
+ doel_instance = class_dict[relation.doel_uri][i]
723
+ if relation.objectUri == 'https://wegenenverkeer.data.vlaanderen.be/ns/onderdeel#HeeftBetrokkene':
724
+ relation_instance = create_betrokkenerelation(rol='toezichter', source=bron_instance,
725
+ target=doel_instance, model_directory=model_directory)
726
+ else:
727
+ if relation.richting == 'Unspecified' and bron_instance.assetId.identificator > doel_instance.assetId.identificator:
728
+ continue
729
+ relation_type = dynamic_create_type_from_uri(class_uri=relation.objectUri, model_directory=model_directory)
730
+ relation_instance = create_relation(relation_type=relation_type, source=bron_instance,
731
+ target=doel_instance, model_directory=model_directory)
732
+
733
+ otl_objects.append(relation_instance)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: otlmow_template
3
- Version: 1.2
3
+ Version: 1.4
4
4
  Author-email: David Vlaminck <david.vlaminck@mow.vlaanderen.be>, Jasper Berton <jasperberton1@telenet.be>
5
5
  License: GNU GENERAL PUBLIC LICENSE
6
6
  Version 3, 29 June 2007
@@ -697,7 +697,7 @@ Classifier: Topic :: Software Development :: Quality Assurance
697
697
  Requires-Python: >=3.9
698
698
  Description-Content-Type: text/markdown
699
699
  License-File: LICENSE
700
- Requires-Dist: otlmow-converter>=1.11
700
+ Requires-Dist: otlmow-converter>=1.14
701
701
  Requires-Dist: otlmow-modelbuilder>=0.27
702
702
  Provides-Extra: test
703
703
  Requires-Dist: pytest; extra == "test"
@@ -0,0 +1,7 @@
1
+ otlmow_template/SubsetTemplateCreator.py,sha256=iZD2kjhOnymQ9tgqU6zq2ZCD8KVIT232mbrxTSR4fQ8,35845
2
+ otlmow_template/Exceptions/MissingTypeUriException.py,sha256=DSKwywmP9Bq8n7rzBoDcEPlxvC1IChx18QIHFUCTtdA,51
3
+ otlmow_template-1.4.dist-info/licenses/LICENSE,sha256=ixuiBLtpoK3iv89l7ylKkg9rs2GzF9ukPH7ynZYzK5s,35148
4
+ otlmow_template-1.4.dist-info/METADATA,sha256=MqaUUEubb-DhKErKteUljO6Z3lxjGlaJoDL4a0cam-k,44220
5
+ otlmow_template-1.4.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
6
+ otlmow_template-1.4.dist-info/top_level.txt,sha256=zPgBoaTLG-avoOLySlwOUEtHaFyA5Vc5wJqkSeX1l6A,16
7
+ otlmow_template-1.4.dist-info/RECORD,,
@@ -1,7 +0,0 @@
1
- otlmow_template/SubsetTemplateCreator.py,sha256=utrlhjvojzCMlQ9yO62H_FnnRL4swksEEBziLlqaD1o,29511
2
- otlmow_template/Exceptions/MissingTypeUriException.py,sha256=DSKwywmP9Bq8n7rzBoDcEPlxvC1IChx18QIHFUCTtdA,51
3
- otlmow_template-1.2.dist-info/licenses/LICENSE,sha256=ixuiBLtpoK3iv89l7ylKkg9rs2GzF9ukPH7ynZYzK5s,35148
4
- otlmow_template-1.2.dist-info/METADATA,sha256=fCISozOC-6u1_Hgn-kQie-gbHDPefyfKgltqH3Rn63Q,44220
5
- otlmow_template-1.2.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
6
- otlmow_template-1.2.dist-info/top_level.txt,sha256=zPgBoaTLG-avoOLySlwOUEtHaFyA5Vc5wJqkSeX1l6A,16
7
- otlmow_template-1.2.dist-info/RECORD,,