pyMetaModel 0.5.3__tar.gz → 0.6.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.
Files changed (107) hide show
  1. {pymetamodel-0.5.3 → pymetamodel-0.6.0}/.github/workflows/build.yml +4 -2
  2. {pymetamodel-0.5.3 → pymetamodel-0.6.0}/PKG-INFO +4 -6
  3. pymetamodel-0.6.0/meta/__init__.py +1 -0
  4. {pymetamodel-0.5.3 → pymetamodel-0.6.0}/meta/metamodel.py +120 -115
  5. {pymetamodel-0.5.3 → pymetamodel-0.6.0}/meta/metamodel_cmd.py +1 -1
  6. {pymetamodel-0.5.3 → pymetamodel-0.6.0}/meta/mw.py +4 -2
  7. {pymetamodel-0.5.3 → pymetamodel-0.6.0}/meta/sidif2linkml.py +4 -1
  8. {pymetamodel-0.5.3 → pymetamodel-0.6.0}/meta/smw_type.py +3 -19
  9. {pymetamodel-0.5.3 → pymetamodel-0.6.0}/meta/uml.py +1 -1
  10. {pymetamodel-0.5.3 → pymetamodel-0.6.0}/pyproject.toml +11 -14
  11. {pymetamodel-0.5.3 → pymetamodel-0.6.0}/tests/test_linkml.py +1 -1
  12. {pymetamodel-0.5.3 → pymetamodel-0.6.0}/tests/test_metamodel.py +4 -4
  13. {pymetamodel-0.5.3 → pymetamodel-0.6.0}/tests/test_mw.py +10 -6
  14. pymetamodel-0.5.3/meta/__init__.py +0 -1
  15. {pymetamodel-0.5.3 → pymetamodel-0.6.0}/.github/workflows/upload-to-pypi.yml +0 -0
  16. {pymetamodel-0.5.3 → pymetamodel-0.6.0}/.gitignore +0 -0
  17. {pymetamodel-0.5.3 → pymetamodel-0.6.0}/.project +0 -0
  18. {pymetamodel-0.5.3 → pymetamodel-0.6.0}/.pydevproject +0 -0
  19. {pymetamodel-0.5.3 → pymetamodel-0.6.0}/LICENSE +0 -0
  20. {pymetamodel-0.5.3 → pymetamodel-0.6.0}/README.md +0 -0
  21. {pymetamodel-0.5.3 → pymetamodel-0.6.0}/docs/index.md +0 -0
  22. {pymetamodel-0.5.3 → pymetamodel-0.6.0}/examples/ceur-ws/ceur-ws.mermaid +0 -0
  23. {pymetamodel-0.5.3 → pymetamodel-0.6.0}/examples/ceur-ws/ceur-ws.puml +0 -0
  24. {pymetamodel-0.5.3 → pymetamodel-0.6.0}/examples/ceur-ws/ceur-ws.py +0 -0
  25. {pymetamodel-0.5.3 → pymetamodel-0.6.0}/examples/ceur-ws/ceur-ws.sidif +0 -0
  26. {pymetamodel-0.5.3 → pymetamodel-0.6.0}/examples/ceur-ws/ceur-ws.xlsx +0 -0
  27. {pymetamodel-0.5.3 → pymetamodel-0.6.0}/examples/ceur-ws/ceur-ws.yaml +0 -0
  28. {pymetamodel-0.5.3 → pymetamodel-0.6.0}/examples/ceur-ws/ceur-ws_puml.txt +0 -0
  29. {pymetamodel-0.5.3 → pymetamodel-0.6.0}/examples/city/city.mermaid +0 -0
  30. {pymetamodel-0.5.3 → pymetamodel-0.6.0}/examples/city/city.puml +0 -0
  31. {pymetamodel-0.5.3 → pymetamodel-0.6.0}/examples/city/city.py +0 -0
  32. {pymetamodel-0.5.3 → pymetamodel-0.6.0}/examples/city/city.sidif +0 -0
  33. {pymetamodel-0.5.3 → pymetamodel-0.6.0}/examples/city/city.xlsx +0 -0
  34. {pymetamodel-0.5.3 → pymetamodel-0.6.0}/examples/city/city.yaml +0 -0
  35. {pymetamodel-0.5.3 → pymetamodel-0.6.0}/examples/city/city_puml.txt +0 -0
  36. {pymetamodel-0.5.3 → pymetamodel-0.6.0}/examples/family/FamilyContext.mermaid +0 -0
  37. {pymetamodel-0.5.3 → pymetamodel-0.6.0}/examples/family/FamilyContext.puml +0 -0
  38. {pymetamodel-0.5.3 → pymetamodel-0.6.0}/examples/family/FamilyContext.py +0 -0
  39. {pymetamodel-0.5.3 → pymetamodel-0.6.0}/examples/family/FamilyContext.sidif +0 -0
  40. {pymetamodel-0.5.3 → pymetamodel-0.6.0}/examples/family/FamilyContext.xlsx +0 -0
  41. {pymetamodel-0.5.3 → pymetamodel-0.6.0}/examples/family/FamilyContext.yaml +0 -0
  42. {pymetamodel-0.5.3 → pymetamodel-0.6.0}/examples/family/FamilyContext_puml.txt +0 -0
  43. {pymetamodel-0.5.3 → pymetamodel-0.6.0}/examples/infrastructure/infrastructure.mermaid +0 -0
  44. {pymetamodel-0.5.3 → pymetamodel-0.6.0}/examples/infrastructure/infrastructure.puml +0 -0
  45. {pymetamodel-0.5.3 → pymetamodel-0.6.0}/examples/infrastructure/infrastructure.py +0 -0
  46. {pymetamodel-0.5.3 → pymetamodel-0.6.0}/examples/infrastructure/infrastructure.sidif +0 -0
  47. {pymetamodel-0.5.3 → pymetamodel-0.6.0}/examples/infrastructure/infrastructure.xlsx +0 -0
  48. {pymetamodel-0.5.3 → pymetamodel-0.6.0}/examples/infrastructure/infrastructure.yaml +0 -0
  49. {pymetamodel-0.5.3 → pymetamodel-0.6.0}/examples/infrastructure/infrastructure_puml.txt +0 -0
  50. {pymetamodel-0.5.3 → pymetamodel-0.6.0}/examples/metamodel/metamodel.mermaid +0 -0
  51. {pymetamodel-0.5.3 → pymetamodel-0.6.0}/examples/metamodel/metamodel.puml +0 -0
  52. {pymetamodel-0.5.3 → pymetamodel-0.6.0}/examples/metamodel/metamodel.py +0 -0
  53. {pymetamodel-0.5.3 → pymetamodel-0.6.0}/examples/metamodel/metamodel.sidif +0 -0
  54. {pymetamodel-0.5.3 → pymetamodel-0.6.0}/examples/metamodel/metamodel.xlsx +0 -0
  55. {pymetamodel-0.5.3 → pymetamodel-0.6.0}/examples/metamodel/metamodel.yaml +0 -0
  56. {pymetamodel-0.5.3 → pymetamodel-0.6.0}/examples/metamodel/metamodel_puml.txt +0 -0
  57. {pymetamodel-0.5.3 → pymetamodel-0.6.0}/examples/scientific-events/scientific-events.mermaid +0 -0
  58. {pymetamodel-0.5.3 → pymetamodel-0.6.0}/examples/scientific-events/scientific-events.puml +0 -0
  59. {pymetamodel-0.5.3 → pymetamodel-0.6.0}/examples/scientific-events/scientific-events.py +0 -0
  60. {pymetamodel-0.5.3 → pymetamodel-0.6.0}/examples/scientific-events/scientific-events.sidif +0 -0
  61. {pymetamodel-0.5.3 → pymetamodel-0.6.0}/examples/scientific-events/scientific-events.xlsx +0 -0
  62. {pymetamodel-0.5.3 → pymetamodel-0.6.0}/examples/scientific-events/scientific-events.yaml +0 -0
  63. {pymetamodel-0.5.3 → pymetamodel-0.6.0}/examples/scientific-events/scientific-events_puml.txt +0 -0
  64. {pymetamodel-0.5.3 → pymetamodel-0.6.0}/examples/smartRQM/smartRQM.mermaid +0 -0
  65. {pymetamodel-0.5.3 → pymetamodel-0.6.0}/examples/smartRQM/smartRQM.puml +0 -0
  66. {pymetamodel-0.5.3 → pymetamodel-0.6.0}/examples/smartRQM/smartRQM.py +0 -0
  67. {pymetamodel-0.5.3 → pymetamodel-0.6.0}/examples/smartRQM/smartRQM.sidif +0 -0
  68. {pymetamodel-0.5.3 → pymetamodel-0.6.0}/examples/smartRQM/smartRQM.yaml +0 -0
  69. {pymetamodel-0.5.3 → pymetamodel-0.6.0}/examples/smartRQM/smartRQM_puml.txt +0 -0
  70. {pymetamodel-0.5.3 → pymetamodel-0.6.0}/examples/smwcon/smwcon.mermaid +0 -0
  71. {pymetamodel-0.5.3 → pymetamodel-0.6.0}/examples/smwcon/smwcon.puml +0 -0
  72. {pymetamodel-0.5.3 → pymetamodel-0.6.0}/examples/smwcon/smwcon.py +0 -0
  73. {pymetamodel-0.5.3 → pymetamodel-0.6.0}/examples/smwcon/smwcon.sidif +0 -0
  74. {pymetamodel-0.5.3 → pymetamodel-0.6.0}/examples/smwcon/smwcon.xlsx +0 -0
  75. {pymetamodel-0.5.3 → pymetamodel-0.6.0}/examples/smwcon/smwcon.yaml +0 -0
  76. {pymetamodel-0.5.3 → pymetamodel-0.6.0}/examples/smwcon/smwcon_puml.txt +0 -0
  77. {pymetamodel-0.5.3 → pymetamodel-0.6.0}/examples/teaching/TeachingSchema.mermaid +0 -0
  78. {pymetamodel-0.5.3 → pymetamodel-0.6.0}/examples/teaching/TeachingSchema.puml +0 -0
  79. {pymetamodel-0.5.3 → pymetamodel-0.6.0}/examples/teaching/TeachingSchema.py +0 -0
  80. {pymetamodel-0.5.3 → pymetamodel-0.6.0}/examples/teaching/TeachingSchema.sidif +0 -0
  81. {pymetamodel-0.5.3 → pymetamodel-0.6.0}/examples/teaching/TeachingSchema.xlsx +0 -0
  82. {pymetamodel-0.5.3 → pymetamodel-0.6.0}/examples/teaching/TeachingSchema.yaml +0 -0
  83. {pymetamodel-0.5.3 → pymetamodel-0.6.0}/examples/teaching/TeachingSchema_puml.txt +0 -0
  84. {pymetamodel-0.5.3 → pymetamodel-0.6.0}/examples/wiki/wiki.mermaid +0 -0
  85. {pymetamodel-0.5.3 → pymetamodel-0.6.0}/examples/wiki/wiki.puml +0 -0
  86. {pymetamodel-0.5.3 → pymetamodel-0.6.0}/examples/wiki/wiki.py +0 -0
  87. {pymetamodel-0.5.3 → pymetamodel-0.6.0}/examples/wiki/wiki.sidif +0 -0
  88. {pymetamodel-0.5.3 → pymetamodel-0.6.0}/examples/wiki/wiki.xlsx +0 -0
  89. {pymetamodel-0.5.3 → pymetamodel-0.6.0}/examples/wiki/wiki.yaml +0 -0
  90. {pymetamodel-0.5.3 → pymetamodel-0.6.0}/examples/wiki/wiki_puml.txt +0 -0
  91. {pymetamodel-0.5.3 → pymetamodel-0.6.0}/meta/profiler.py +0 -0
  92. {pymetamodel-0.5.3 → pymetamodel-0.6.0}/meta/version.py +0 -0
  93. {pymetamodel-0.5.3 → pymetamodel-0.6.0}/metamodel.puml +0 -0
  94. {pymetamodel-0.5.3 → pymetamodel-0.6.0}/mkdocs.yml +0 -0
  95. {pymetamodel-0.5.3 → pymetamodel-0.6.0}/scripts/blackisort +0 -0
  96. {pymetamodel-0.5.3 → pymetamodel-0.6.0}/scripts/doc +0 -0
  97. {pymetamodel-0.5.3 → pymetamodel-0.6.0}/scripts/genexamples +0 -0
  98. {pymetamodel-0.5.3 → pymetamodel-0.6.0}/scripts/install +0 -0
  99. {pymetamodel-0.5.3 → pymetamodel-0.6.0}/scripts/release +0 -0
  100. {pymetamodel-0.5.3 → pymetamodel-0.6.0}/scripts/test +0 -0
  101. {pymetamodel-0.5.3 → pymetamodel-0.6.0}/tests/__init__.py +0 -0
  102. {pymetamodel-0.5.3 → pymetamodel-0.6.0}/tests/basemwtest.py +0 -0
  103. {pymetamodel-0.5.3 → pymetamodel-0.6.0}/tests/basesmwtest.py +0 -0
  104. {pymetamodel-0.5.3 → pymetamodel-0.6.0}/tests/basetest.py +0 -0
  105. {pymetamodel-0.5.3 → pymetamodel-0.6.0}/tests/test_generators.py +0 -0
  106. {pymetamodel-0.5.3 → pymetamodel-0.6.0}/tests/test_plantuml.py +0 -0
  107. {pymetamodel-0.5.3 → pymetamodel-0.6.0}/tests/test_sidif.py +0 -0
@@ -18,8 +18,10 @@ jobs:
18
18
  runs-on: ubuntu-latest
19
19
  strategy:
20
20
  matrix:
21
- os: [ubuntu-latest, macos-latest, windows-latest]
22
- python-version: [ '3.9', '3.10', '3.11', '3.12' ]
21
+ #os: [ubuntu-latest, macos-latest, windows-latest]
22
+ os: [ubuntu-latest]
23
+ #python-version: [ '3.9', '3.10', '3.11', '3.12' ]
24
+ python-version: [ '3.12' ]
23
25
 
24
26
  steps:
25
27
  - uses: actions/checkout@v4
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pyMetaModel
3
- Version: 0.5.3
3
+ Version: 0.6.0
4
4
  Dynamic: Summary
5
5
  Project-URL: Home, https://github.com/WolfgangFahl/pyMetaModel
6
6
  Project-URL: Documentation, https://wiki.bitplan.com/index.php/PyMetaModel
@@ -216,20 +216,18 @@ Classifier: Intended Audience :: Science/Research
216
216
  Classifier: License :: OSI Approved :: Apache Software License
217
217
  Classifier: Operating System :: OS Independent
218
218
  Classifier: Programming Language :: Python :: 3 :: Only
219
- Classifier: Programming Language :: Python :: 3.9
220
219
  Classifier: Programming Language :: Python :: 3.10
221
220
  Classifier: Programming Language :: Python :: 3.11
222
221
  Classifier: Programming Language :: Python :: 3.12
222
+ Classifier: Programming Language :: Python :: 3.13
223
223
  Classifier: Topic :: Software Development
224
- Requires-Python: >=3.9
225
- Requires-Dist: dacite>=1.8.1
224
+ Requires-Python: >=3.10
226
225
  Requires-Dist: py-sidif>=0.2.0
226
+ Requires-Dist: pybasemkit>=0.0.4
227
227
  Requires-Dist: urllib3
228
228
  Provides-Extra: linkml
229
229
  Requires-Dist: linkml-runtime>=1.8.3; extra == 'linkml'
230
230
  Requires-Dist: linkml>=1.8.5; extra == 'linkml'
231
- Provides-Extra: lodstorage
232
- Requires-Dist: pylodstorage>=0.13.3; extra == 'lodstorage'
233
231
  Provides-Extra: smw
234
232
  Requires-Dist: mwparserfromhell>=0.6.6; extra == 'smw'
235
233
  Requires-Dist: py-3rdparty-mediawiki>=0.14.0; extra == 'smw'
@@ -0,0 +1 @@
1
+ __version__ = "0.6.0"
@@ -4,66 +4,40 @@ Created on 2022-11-23
4
4
  @author: wf
5
5
  """
6
6
 
7
+ from dataclasses import field
8
+ from datetime import datetime
7
9
  import sys
10
+ from typing import List, Optional, Tuple, Dict
8
11
  import typing
9
- from datetime import datetime
10
- from typing import List, Optional, Tuple
11
-
12
- import urllib3
13
- from lodstorage.jsonable import JSONAble
14
- from sidif.sidif import SiDIFParser
15
12
 
13
+ from basemkit.persistent_log import Log
14
+ from basemkit.yamlable import lod_storable
16
15
  from meta.mw import MediaWikiContext
16
+ from meta.smw_type import SMW_Type
17
+ from sidif.sidif import SiDIFParser
18
+ import urllib3
17
19
 
18
20
 
19
- class MetaModelElement(JSONAble):
20
- """
21
- a generic MetaModelElement
22
-
23
- to handle the technicalities of being a MetaModelElement so that derived
24
- MetaModelElements can focus on the MetaModel domain specific aspects
25
- """
26
-
27
- def __init__(self):
28
- """
29
- construct me
30
- """
31
- self.__metamodel_props = {}
32
- cls = self.__class__
33
- if hasattr(cls, "getSamples"):
34
- for sample in cls.getSamples():
35
- for key in sample.keys():
36
- if not key in self.__metamodel_props:
37
- self.__metamodel_props[key] = key # Property(self,key)
38
-
39
- def __str__(self):
40
- """
41
- get a string representation of me
42
- """
43
- text = self.__class__.__name__
44
- for prop_name in self.__metamodel_props.keys():
45
- if not isinstance(prop_name, str):
46
- pass
47
- elif hasattr(self, prop_name):
48
- value = getattr(self, prop_name)
49
- text += f"\n {prop_name}={str(value)}"
50
- return text
51
-
52
21
 
53
- class Context(MetaModelElement):
22
+ @lod_storable
23
+ class Context:
54
24
  """
55
25
  A Context groups some topics like a Namespace/Package.
56
26
  This class provides helper functions and constants to render a Context to corresponding wiki pages
57
27
  """
58
-
59
- def __init__(self):
60
- """
61
- constructor
62
- """
63
- MetaModelElement.__init__(self)
64
- self.topics = {}
65
- self.types = {}
66
- self.errors = []
28
+ name: Optional[str] = None
29
+ since: Optional[str] = None # isodate string
30
+ updated: Optional[str] = None # isodate string
31
+ copyright: Optional[str] = None
32
+ master: Optional[str] = None
33
+ demo: Optional[str] = None
34
+ topics: Dict[str, 'Topic'] = field(default_factory=dict)
35
+ types: Dict[str, 'Topic'] = field(default_factory=dict)
36
+ errors: List[str] = field(default_factory=list)
37
+
38
+ def __post_init__(self):
39
+ self.log=Log()
40
+ pass
67
41
 
68
42
  @classmethod
69
43
  def getSamples(cls):
@@ -72,7 +46,7 @@ class Context(MetaModelElement):
72
46
  "name": "MetaModel",
73
47
  "since": datetime.strptime("2015-01-23", "%Y-%m-%d"),
74
48
  "updated": datetime.strptime("2024-08-07", "%Y-%m-%d"),
75
- "copyright": "2015-2024 BITPlan GmbH",
49
+ "copyright": "2015-2025 BITPlan GmbH",
76
50
  "master": "https://contexts.bitplan.com",
77
51
  "demo": "https://wiki.bitplan.com/index.php/List_of_Contexts"
78
52
  }
@@ -226,51 +200,53 @@ class Context(MetaModelElement):
226
200
  """
227
201
  context = None
228
202
  for key, record in did.items():
229
- isA = record.get("isA")
230
- if isA == "Context":
231
- context = Context()
232
- context.fromDict(record)
233
- context.sanitize(key)
234
- elif isA == "TopicLink":
235
- """
236
- # Event n : 1 City
237
- Event_in_City isA TopicLink
238
- "eventInCity" is name of it
239
- "city" is sourceRole of it
240
- false is sourceMultiple of it
241
- "City" is source of it
242
- "event" is targetRole of it
243
- true is targetMultiple of it
244
- "Event" is target of it
245
- """
246
- tl = TopicLink()
247
- tl.fromDict(record)
248
- context.addLink(tl)
249
- elif isA == "Property":
250
- prop = Property()
251
- prop.isLink = False
252
- prop.fromDict(record)
253
- prop.sanitize()
254
- context.addProperty(prop)
255
- else: # isA == Topic or in declared topics
256
- topic = Topic()
257
- topic.fromDict(record)
258
- topic.sanitize()
259
- if context is None:
260
- context = Context()
261
- context.name = "GlobalContext"
262
- context.since = "2022-11-26"
263
- context.master = "http://contexts.bitplan.com"
264
- context.error(f"topic {topic.name} has no defined context")
265
- if hasattr(topic, "name"):
266
- context.topics[topic.name] = topic
267
- topic.context_obj=context
268
- elif hasattr(topic, "type"):
269
- context.types[topic.type]=topic
203
+ try:
204
+ isA = record.get("isA")
205
+ if isA == "Context":
206
+ context = Context.from_dict2(record)
207
+ context.sanitize(key)
208
+ elif isA == "TopicLink":
209
+ """
210
+ # Event n : 1 City
211
+ Event_in_City isA TopicLink
212
+ "eventInCity" is name of it
213
+ "city" is sourceRole of it
214
+ false is sourceMultiple of it
215
+ "City" is source of it
216
+ "event" is targetRole of it
217
+ true is targetMultiple of it
218
+ "Event" is target of it
219
+ """
220
+ tl = TopicLink.from_dict2(record)
221
+ context.addLink(tl)
222
+ elif isA == "Property":
223
+ prop = Property.from_dict2(record)
224
+ prop.sanitize()
225
+ context.addProperty(prop)
226
+ elif isA == "SMW_Type":
227
+ smw_type=SMW_Type.from_dict2(record) # @UndefinedVariable
228
+ context.types[smw_type.type]=smw_type
229
+ else: # isA == Topic or in declared topics
230
+ topic = Topic.from_dict2(record)
231
+ topic.sanitize()
232
+ if context is None:
233
+ context = Context()
234
+ context.name = "GlobalContext"
235
+ context.since = "2022-11-26"
236
+ context.master = "http://contexts.bitplan.com"
237
+ context.error(f"topic {topic.name} has no defined context")
238
+ if hasattr(topic, "name") and topic.name:
239
+ context.topics[topic.name] = topic
240
+ topic.context_obj=context
241
+ else:
242
+ # potential foreign or extends declaration
243
+ context.error(f"missing name for topic {topic} {key} - foreign declaration?")
244
+ except Exception as ex:
245
+ if context:
246
+ msg=f"invalid dict {record}: {str(ex)}"
247
+ context.log.log("❌","dict",msg)
270
248
  else:
271
- # potential foreign or extends declaration
272
- context.error(f"missing name for topic {topic} {key} - foreign declaration?")
273
-
249
+ raise ex
274
250
  # link topic to concepts and add topicLinks
275
251
  for topic in context.topics.values():
276
252
  topic.setConceptProperty()
@@ -356,8 +332,9 @@ class Context(MetaModelElement):
356
332
  error = None
357
333
  errMsg = None
358
334
  sidif = None
335
+ msg=f"reading sidif for {mw_context.context} from {mw_context.wikiId}"
359
336
  if debug:
360
- print(f"reading sidif for {mw_context.context} from {mw_context.wikiId}")
337
+ print(msg)
361
338
  try:
362
339
  sidif = mw_context.read_sidif()
363
340
  except BaseException as ex:
@@ -367,24 +344,29 @@ class Context(MetaModelElement):
367
344
  context, error, errMsg = cls.fromSiDIF(
368
345
  sidif=sidif, title=mw_context.wikiId, depth=depth, debug=debug
369
346
  )
347
+ else:
348
+ errMsg=f"{msg} failed"
349
+ error=ValueError(msg)
370
350
  return context, error, errMsg
371
351
 
372
-
373
- class Topic(MetaModelElement):
352
+ @lod_storable
353
+ class Topic:
374
354
  """
375
355
  A Topic is a Concept/Class/Thing/Entity
376
356
  """
357
+ name: Optional[str] = None
358
+ _pluralName: Optional[str] = None
359
+ documentation: Optional[str] = None
360
+ wikiDocumentation: Optional[str] = None
361
+ defaultstoremode: str = "property"
362
+ extends: Optional[str] = None
363
+ context_obj: Optional[Context] = None
364
+ conceptProperty: Optional['Property'] = None
365
+ listLimit: int = 200
366
+ properties: Dict[str, 'Property'] = field(default_factory=dict)
367
+ sourceTopicLinks: Dict[str, 'TopicLink'] = field(default_factory=dict)
368
+ targetTopicLinks: Dict[str, 'TopicLink'] = field(default_factory=dict)
377
369
 
378
- def __init__(self):
379
- """
380
- constructor
381
- """
382
- MetaModelElement.__init__(self)
383
- self._pluralName = None # Initialize with underscore to indicate a protected attribute
384
-
385
- self.properties = {}
386
- self.sourceTopicLinks = {}
387
- self.targetTopicLinks = {}
388
370
 
389
371
  def get_extends_topics(self, l: List['Topic'] = None) -> List['Topic']:
390
372
  """
@@ -570,7 +552,7 @@ class Topic(MetaModelElement):
570
552
  props_count = len(props)
571
553
 
572
554
  # Sort properties locally by index
573
- sorted_props = sorted(props, key=lambda p: getattr(p, 'index', props_count))
555
+ sorted_props = sorted(props, key=lambda p: p.index or props_count)
574
556
 
575
557
  return sorted_props
576
558
 
@@ -638,16 +620,26 @@ class Topic(MetaModelElement):
638
620
  markup += f"""{self.askSort()}}}}}"""
639
621
  return markup
640
622
 
641
- class Property(MetaModelElement):
623
+ @lod_storable
624
+ class Property:
642
625
  """
643
626
  Provides helper functions and constants for properties
644
627
  """
628
+ name: Optional[str] = None
629
+ label: Optional[str] = None
630
+ type: Optional[str] = None
631
+ topic: Optional[str] = None
632
+ documentation: Optional[str] = None
633
+ namespace: str = "Property"
634
+ showInGrid: bool = True
635
+ isLink: bool = False
636
+ topicLink: Optional['TopicLink'] = None
637
+ index: Optional[int] = None
638
+ sortPos: Optional[int] = None
639
+ primaryKey: bool = False
640
+ mandatory: bool = False
641
+ sortAscending: bool = True
645
642
 
646
- def __init__(self):
647
- """
648
- constructor
649
- """
650
- MetaModelElement.__init__(self)
651
643
 
652
644
  @classmethod
653
645
  def getSamples(cls):
@@ -702,11 +694,24 @@ class Property(MetaModelElement):
702
694
  self.showInGrid=True
703
695
  pass
704
696
 
705
- class TopicLink(MetaModelElement):
697
+ @lod_storable
698
+ class TopicLink:
706
699
  """
707
700
  A TopicLink links two Concepts/Topics
708
701
  """
709
702
 
703
+ name: Optional[str] = None
704
+ source: Optional[str] = None
705
+ target: Optional[str] = None
706
+ sourceRole: Optional[str] = None
707
+ targetRole: Optional[str] = None
708
+ sourceMultiple: bool = False
709
+ targetMultiple: bool = False
710
+ sourceDocumentation: Optional[str] = None
711
+ targetDocumentation: Optional[str] = None
712
+ sourceTopic: Optional[Topic] = None
713
+ targetTopic: Optional[Topic] = None
714
+
710
715
  @classmethod
711
716
  def getSamples(cls):
712
717
  samples = [
@@ -43,7 +43,7 @@ class MetaModelCmd:
43
43
  program_license = """%s
44
44
 
45
45
  Created by %s on %s.
46
- Copyright 2022-2024 Wolfgang Fahl. All rights reserved.
46
+ Copyright 2022-2025 Wolfgang Fahl. All rights reserved.
47
47
 
48
48
  Licensed under the Apache License 2.0
49
49
  http://www.apache.org/licenses/LICENSE-2.0
@@ -1,5 +1,5 @@
1
1
  """
2
- Created on 23.11.2022
2
+ Created on 2022-11-23
3
3
 
4
4
  @author: wf
5
5
  """
@@ -40,7 +40,9 @@ class MediaWikiContext:
40
40
  """
41
41
  sidif = None
42
42
  wikiusers = WikiUser.getWikiUsers(lenient=True)
43
- if self.wikiId in wikiusers:
43
+ if not self.wikiId in wikiusers:
44
+ raise ValueError(f"unknown wiki {self.wikiId}")
45
+ else:
44
46
  wikiUser = wikiusers[self.wikiId]
45
47
  self.wikiClient = WikiClient.ofWikiId(wikiUser.wikiId)
46
48
  if self.wikiClient.needsLogin():
@@ -50,6 +50,8 @@ class SiDIF2LinkML:
50
50
  master = "http://example.com"
51
51
  uri = f"{master}/{context.name}"
52
52
  for topic in self.context.topics.values():
53
+ if not topic.name:
54
+ continue
53
55
  cd = ClassDefinition(name=topic.name)
54
56
  cd.description = topic.documentation
55
57
  sv.add_class(cd)
@@ -59,7 +61,8 @@ class SiDIF2LinkML:
59
61
  qname = prop.name
60
62
  if prop.name in sd.slots:
61
63
  slot = sd.slots[prop.name]
62
- slot.description += "," + prop.documentation
64
+ if prop.documentation:
65
+ slot.description += "," + prop.documentation
63
66
  else:
64
67
  qname = f"{topic.name}{delim}{prop.name}"
65
68
  if slot is None:
@@ -1,10 +1,8 @@
1
- from dataclasses import dataclass
2
1
  from typing import Optional
3
2
 
4
- import dacite
3
+ from basemkit.yamlable import lod_storable
5
4
 
6
-
7
- @dataclass
5
+ @lod_storable
8
6
  class SMW_Type:
9
7
  """
10
8
  an SMW_Type is a data type which determines the possible values for that type e.g. a Boolean can hold true/false values while a Number can hold 3.1459 or 20. A Page can hold the name of a Wiki page see https://semantic-mediawiki.org/wiki/Help:List_of_datatypes
@@ -40,18 +38,4 @@ class SMW_Type:
40
38
  |?SMW_Type javaType = javaType
41
39
  | limit=200
42
40
  }}"""
43
- return ask
44
-
45
- @classmethod
46
- def fromDict(cls, data: dict)->'SMW_Type':
47
- """
48
- create a SMW_Type from the given dict
49
-
50
- Args:
51
- data (dict): the dict to create the SMW_Type from
52
-
53
- Returns:
54
- SMW_Type: the freshly created SMW_Type
55
- """
56
- smw_type = dacite.from_dict(data_class=cls, data=data)
57
- return smw_type
41
+ return ask
@@ -17,7 +17,7 @@ class PlantUml(object):
17
17
  # redundant to skinparams in pylodstorage.uml
18
18
  skinparams = """
19
19
  ' BITPlan Corporate identity skin params
20
- ' Copyright (c) 2015-2024 BITPlan GmbH
20
+ ' Copyright (c) 2015-2025 BITPlan GmbH
21
21
  ' see http://wiki.bitplan.com/PlantUmlSkinParams#BITPlanCI
22
22
  ' skinparams generated by com.bitplan.restmodelmanager
23
23
  skinparam note {
@@ -17,23 +17,25 @@ readme = "README.md"
17
17
  # flit_core.config.ConfigError: license field should be <class 'dict'>, not <class 'str'>
18
18
  license = { file="LICENSE" }
19
19
  dependencies = [
20
- # https://pypi.org/project/py-sidif/
21
- 'py-sidif>=0.2.0',
22
- # https://github.com/urllib3/urllib3
23
- 'urllib3',
24
- # https://github.com/konradhalas/dacite
25
- 'dacite>=1.8.1',
26
- ]
20
+ # https://pypi.org/project/pybasemkit/
21
+ # https://github.com/WolfgangFahl/pybasemkit
22
+ # Python base module kit: YAML/JSON I/O, structured logging, CLI tooling, shell execution, and remote pydevd debug support.
23
+ "pybasemkit>=0.0.4",
24
+ # https://pypi.org/project/py-sidif/
25
+ 'py-sidif>=0.2.0',
26
+ # https://github.com/urllib3/urllib3
27
+ 'urllib3',
28
+ ]
27
29
 
28
- requires-python = ">=3.9"
30
+ requires-python = ">=3.10"
29
31
  classifiers=[
30
32
  "Development Status :: 4 - Beta",
31
33
  "Environment :: Web Environment",
32
34
  "Programming Language :: Python :: 3 :: Only",
33
- "Programming Language :: Python :: 3.9",
34
35
  "Programming Language :: Python :: 3.10",
35
36
  "Programming Language :: Python :: 3.11",
36
37
  "Programming Language :: Python :: 3.12",
38
+ "Programming Language :: Python :: 3.13",
37
39
  "Operating System :: OS Independent",
38
40
  "Topic :: Software Development",
39
41
  "Intended Audience :: Developers",
@@ -53,11 +55,6 @@ Source = "https://github.com/WolfgangFahl/pyMetaModel"
53
55
  test = [
54
56
  "green",
55
57
  ]
56
- # python List of Dict (Table) Storage library
57
- lodstorage = [
58
- # https://pypi.org/project/pylodstorage/
59
- 'pyLodStorage>=0.13.3',
60
- ]
61
58
  # LinkML support
62
59
  # https://linkml.io/
63
60
  linkml = [
@@ -29,7 +29,7 @@ class TestLinkML(BaseMediawikiTest):
29
29
  test conversion from SiDIF to LinkML
30
30
  """
31
31
  debug = self.debug
32
- debug = True
32
+ #debug = True
33
33
  parser = MetaModelCmd.getArgParser()
34
34
  mm_cmd = MetaModelCmd(debug=debug)
35
35
  for wikiId, context_name in [("wiki", "MetaModel"), ("cr", "CrSchema")]:
@@ -25,12 +25,12 @@ class TestMetaModel(BaseMediawikiTest):
25
25
  """
26
26
  test SMW_Type handling
27
27
  """
28
- debug = True
28
+ debug = self.debug
29
29
  smwAccess = self.smwAccessMap["wiki"]
30
30
  ask_query = SMW_Type.askQuery()
31
31
  did = smwAccess.smw.query(ask_query)
32
32
  for record in did.values():
33
- smw_Type = SMW_Type.fromDict(record)
33
+ smw_type = SMW_Type.from_dict(record) # @UndefinedVariable
34
34
  if debug:
35
- print(smw_Type)
36
- pass
35
+ print(smw_type)
36
+ self.assertIsInstance(smw_type, SMW_Type)
@@ -7,7 +7,7 @@ Created on 2022-11-23
7
7
  import json
8
8
 
9
9
  from wikibot3rd.wikiuser import WikiUser
10
-
10
+ from tqdm import tqdm
11
11
  from meta.metamodel import Context
12
12
  from tests.basesmwtest import BaseSemanticMediawikiTest
13
13
 
@@ -137,13 +137,17 @@ class TestMediawiki(BaseSemanticMediawikiTest):
137
137
  """
138
138
  test reading meta models from wikis
139
139
  """
140
- debug = True
140
+ debug = False
141
141
  lenient = True
142
- for wikiId in WikiUser.getWikiUsers(lenient=True):
142
+ with_progress=False
143
+ wiki_users = WikiUser.getWikiUsers(lenient=True)
144
+ wiki_iter = tqdm(wiki_users, desc="Wikis") if with_progress else wiki_users
145
+ for wikiId in wiki_iter:
143
146
  _smwAccess, mw_contexts = self.check_contexts(wikiId)
144
147
  for context_name in mw_contexts:
148
+ context_info=f"{context_name}@{wikiId}"
145
149
  if debug:
146
- print(f"reading context {context_name} from wiki {wikiId}")
150
+ print(f"reading context {context_info}")
147
151
  cc = self.getContextContext(wikiId=wikiId, context_name=context_name)
148
152
  context = cc.context
149
153
  if not lenient:
@@ -156,8 +160,8 @@ class TestMediawiki(BaseSemanticMediawikiTest):
156
160
  print(context)
157
161
  for _name, topic in context.topics.items():
158
162
  print(topic)
159
- for _name, property in topic.properties.items():
160
- print(property)
163
+ for _name, prop in topic.properties.items():
164
+ print(prop)
161
165
  if len(context.errors) > 0:
162
166
  for error in context.errors:
163
167
  print(error)
@@ -1 +0,0 @@
1
- __version__ = "0.5.3"
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