pyMetaModel 0.5.3__tar.gz → 0.6.1__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.1}/.github/workflows/build.yml +4 -2
  2. {pymetamodel-0.5.3 → pymetamodel-0.6.1}/PKG-INFO +4 -6
  3. pymetamodel-0.6.1/meta/__init__.py +1 -0
  4. {pymetamodel-0.5.3 → pymetamodel-0.6.1}/meta/metamodel.py +124 -115
  5. {pymetamodel-0.5.3 → pymetamodel-0.6.1}/meta/metamodel_cmd.py +1 -1
  6. {pymetamodel-0.5.3 → pymetamodel-0.6.1}/meta/mw.py +4 -2
  7. {pymetamodel-0.5.3 → pymetamodel-0.6.1}/meta/sidif2linkml.py +4 -1
  8. {pymetamodel-0.5.3 → pymetamodel-0.6.1}/meta/smw_type.py +3 -19
  9. {pymetamodel-0.5.3 → pymetamodel-0.6.1}/meta/uml.py +1 -1
  10. {pymetamodel-0.5.3 → pymetamodel-0.6.1}/meta/version.py +1 -1
  11. {pymetamodel-0.5.3 → pymetamodel-0.6.1}/pyproject.toml +11 -14
  12. {pymetamodel-0.5.3 → pymetamodel-0.6.1}/tests/test_linkml.py +1 -1
  13. {pymetamodel-0.5.3 → pymetamodel-0.6.1}/tests/test_metamodel.py +4 -4
  14. {pymetamodel-0.5.3 → pymetamodel-0.6.1}/tests/test_mw.py +10 -6
  15. pymetamodel-0.5.3/meta/__init__.py +0 -1
  16. {pymetamodel-0.5.3 → pymetamodel-0.6.1}/.github/workflows/upload-to-pypi.yml +0 -0
  17. {pymetamodel-0.5.3 → pymetamodel-0.6.1}/.gitignore +0 -0
  18. {pymetamodel-0.5.3 → pymetamodel-0.6.1}/.project +0 -0
  19. {pymetamodel-0.5.3 → pymetamodel-0.6.1}/.pydevproject +0 -0
  20. {pymetamodel-0.5.3 → pymetamodel-0.6.1}/LICENSE +0 -0
  21. {pymetamodel-0.5.3 → pymetamodel-0.6.1}/README.md +0 -0
  22. {pymetamodel-0.5.3 → pymetamodel-0.6.1}/docs/index.md +0 -0
  23. {pymetamodel-0.5.3 → pymetamodel-0.6.1}/examples/ceur-ws/ceur-ws.mermaid +0 -0
  24. {pymetamodel-0.5.3 → pymetamodel-0.6.1}/examples/ceur-ws/ceur-ws.puml +0 -0
  25. {pymetamodel-0.5.3 → pymetamodel-0.6.1}/examples/ceur-ws/ceur-ws.py +0 -0
  26. {pymetamodel-0.5.3 → pymetamodel-0.6.1}/examples/ceur-ws/ceur-ws.sidif +0 -0
  27. {pymetamodel-0.5.3 → pymetamodel-0.6.1}/examples/ceur-ws/ceur-ws.xlsx +0 -0
  28. {pymetamodel-0.5.3 → pymetamodel-0.6.1}/examples/ceur-ws/ceur-ws.yaml +0 -0
  29. {pymetamodel-0.5.3 → pymetamodel-0.6.1}/examples/ceur-ws/ceur-ws_puml.txt +0 -0
  30. {pymetamodel-0.5.3 → pymetamodel-0.6.1}/examples/city/city.mermaid +0 -0
  31. {pymetamodel-0.5.3 → pymetamodel-0.6.1}/examples/city/city.puml +0 -0
  32. {pymetamodel-0.5.3 → pymetamodel-0.6.1}/examples/city/city.py +0 -0
  33. {pymetamodel-0.5.3 → pymetamodel-0.6.1}/examples/city/city.sidif +0 -0
  34. {pymetamodel-0.5.3 → pymetamodel-0.6.1}/examples/city/city.xlsx +0 -0
  35. {pymetamodel-0.5.3 → pymetamodel-0.6.1}/examples/city/city.yaml +0 -0
  36. {pymetamodel-0.5.3 → pymetamodel-0.6.1}/examples/city/city_puml.txt +0 -0
  37. {pymetamodel-0.5.3 → pymetamodel-0.6.1}/examples/family/FamilyContext.mermaid +0 -0
  38. {pymetamodel-0.5.3 → pymetamodel-0.6.1}/examples/family/FamilyContext.puml +0 -0
  39. {pymetamodel-0.5.3 → pymetamodel-0.6.1}/examples/family/FamilyContext.py +0 -0
  40. {pymetamodel-0.5.3 → pymetamodel-0.6.1}/examples/family/FamilyContext.sidif +0 -0
  41. {pymetamodel-0.5.3 → pymetamodel-0.6.1}/examples/family/FamilyContext.xlsx +0 -0
  42. {pymetamodel-0.5.3 → pymetamodel-0.6.1}/examples/family/FamilyContext.yaml +0 -0
  43. {pymetamodel-0.5.3 → pymetamodel-0.6.1}/examples/family/FamilyContext_puml.txt +0 -0
  44. {pymetamodel-0.5.3 → pymetamodel-0.6.1}/examples/infrastructure/infrastructure.mermaid +0 -0
  45. {pymetamodel-0.5.3 → pymetamodel-0.6.1}/examples/infrastructure/infrastructure.puml +0 -0
  46. {pymetamodel-0.5.3 → pymetamodel-0.6.1}/examples/infrastructure/infrastructure.py +0 -0
  47. {pymetamodel-0.5.3 → pymetamodel-0.6.1}/examples/infrastructure/infrastructure.sidif +0 -0
  48. {pymetamodel-0.5.3 → pymetamodel-0.6.1}/examples/infrastructure/infrastructure.xlsx +0 -0
  49. {pymetamodel-0.5.3 → pymetamodel-0.6.1}/examples/infrastructure/infrastructure.yaml +0 -0
  50. {pymetamodel-0.5.3 → pymetamodel-0.6.1}/examples/infrastructure/infrastructure_puml.txt +0 -0
  51. {pymetamodel-0.5.3 → pymetamodel-0.6.1}/examples/metamodel/metamodel.mermaid +0 -0
  52. {pymetamodel-0.5.3 → pymetamodel-0.6.1}/examples/metamodel/metamodel.puml +0 -0
  53. {pymetamodel-0.5.3 → pymetamodel-0.6.1}/examples/metamodel/metamodel.py +0 -0
  54. {pymetamodel-0.5.3 → pymetamodel-0.6.1}/examples/metamodel/metamodel.sidif +0 -0
  55. {pymetamodel-0.5.3 → pymetamodel-0.6.1}/examples/metamodel/metamodel.xlsx +0 -0
  56. {pymetamodel-0.5.3 → pymetamodel-0.6.1}/examples/metamodel/metamodel.yaml +0 -0
  57. {pymetamodel-0.5.3 → pymetamodel-0.6.1}/examples/metamodel/metamodel_puml.txt +0 -0
  58. {pymetamodel-0.5.3 → pymetamodel-0.6.1}/examples/scientific-events/scientific-events.mermaid +0 -0
  59. {pymetamodel-0.5.3 → pymetamodel-0.6.1}/examples/scientific-events/scientific-events.puml +0 -0
  60. {pymetamodel-0.5.3 → pymetamodel-0.6.1}/examples/scientific-events/scientific-events.py +0 -0
  61. {pymetamodel-0.5.3 → pymetamodel-0.6.1}/examples/scientific-events/scientific-events.sidif +0 -0
  62. {pymetamodel-0.5.3 → pymetamodel-0.6.1}/examples/scientific-events/scientific-events.xlsx +0 -0
  63. {pymetamodel-0.5.3 → pymetamodel-0.6.1}/examples/scientific-events/scientific-events.yaml +0 -0
  64. {pymetamodel-0.5.3 → pymetamodel-0.6.1}/examples/scientific-events/scientific-events_puml.txt +0 -0
  65. {pymetamodel-0.5.3 → pymetamodel-0.6.1}/examples/smartRQM/smartRQM.mermaid +0 -0
  66. {pymetamodel-0.5.3 → pymetamodel-0.6.1}/examples/smartRQM/smartRQM.puml +0 -0
  67. {pymetamodel-0.5.3 → pymetamodel-0.6.1}/examples/smartRQM/smartRQM.py +0 -0
  68. {pymetamodel-0.5.3 → pymetamodel-0.6.1}/examples/smartRQM/smartRQM.sidif +0 -0
  69. {pymetamodel-0.5.3 → pymetamodel-0.6.1}/examples/smartRQM/smartRQM.yaml +0 -0
  70. {pymetamodel-0.5.3 → pymetamodel-0.6.1}/examples/smartRQM/smartRQM_puml.txt +0 -0
  71. {pymetamodel-0.5.3 → pymetamodel-0.6.1}/examples/smwcon/smwcon.mermaid +0 -0
  72. {pymetamodel-0.5.3 → pymetamodel-0.6.1}/examples/smwcon/smwcon.puml +0 -0
  73. {pymetamodel-0.5.3 → pymetamodel-0.6.1}/examples/smwcon/smwcon.py +0 -0
  74. {pymetamodel-0.5.3 → pymetamodel-0.6.1}/examples/smwcon/smwcon.sidif +0 -0
  75. {pymetamodel-0.5.3 → pymetamodel-0.6.1}/examples/smwcon/smwcon.xlsx +0 -0
  76. {pymetamodel-0.5.3 → pymetamodel-0.6.1}/examples/smwcon/smwcon.yaml +0 -0
  77. {pymetamodel-0.5.3 → pymetamodel-0.6.1}/examples/smwcon/smwcon_puml.txt +0 -0
  78. {pymetamodel-0.5.3 → pymetamodel-0.6.1}/examples/teaching/TeachingSchema.mermaid +0 -0
  79. {pymetamodel-0.5.3 → pymetamodel-0.6.1}/examples/teaching/TeachingSchema.puml +0 -0
  80. {pymetamodel-0.5.3 → pymetamodel-0.6.1}/examples/teaching/TeachingSchema.py +0 -0
  81. {pymetamodel-0.5.3 → pymetamodel-0.6.1}/examples/teaching/TeachingSchema.sidif +0 -0
  82. {pymetamodel-0.5.3 → pymetamodel-0.6.1}/examples/teaching/TeachingSchema.xlsx +0 -0
  83. {pymetamodel-0.5.3 → pymetamodel-0.6.1}/examples/teaching/TeachingSchema.yaml +0 -0
  84. {pymetamodel-0.5.3 → pymetamodel-0.6.1}/examples/teaching/TeachingSchema_puml.txt +0 -0
  85. {pymetamodel-0.5.3 → pymetamodel-0.6.1}/examples/wiki/wiki.mermaid +0 -0
  86. {pymetamodel-0.5.3 → pymetamodel-0.6.1}/examples/wiki/wiki.puml +0 -0
  87. {pymetamodel-0.5.3 → pymetamodel-0.6.1}/examples/wiki/wiki.py +0 -0
  88. {pymetamodel-0.5.3 → pymetamodel-0.6.1}/examples/wiki/wiki.sidif +0 -0
  89. {pymetamodel-0.5.3 → pymetamodel-0.6.1}/examples/wiki/wiki.xlsx +0 -0
  90. {pymetamodel-0.5.3 → pymetamodel-0.6.1}/examples/wiki/wiki.yaml +0 -0
  91. {pymetamodel-0.5.3 → pymetamodel-0.6.1}/examples/wiki/wiki_puml.txt +0 -0
  92. {pymetamodel-0.5.3 → pymetamodel-0.6.1}/meta/profiler.py +0 -0
  93. {pymetamodel-0.5.3 → pymetamodel-0.6.1}/metamodel.puml +0 -0
  94. {pymetamodel-0.5.3 → pymetamodel-0.6.1}/mkdocs.yml +0 -0
  95. {pymetamodel-0.5.3 → pymetamodel-0.6.1}/scripts/blackisort +0 -0
  96. {pymetamodel-0.5.3 → pymetamodel-0.6.1}/scripts/doc +0 -0
  97. {pymetamodel-0.5.3 → pymetamodel-0.6.1}/scripts/genexamples +0 -0
  98. {pymetamodel-0.5.3 → pymetamodel-0.6.1}/scripts/install +0 -0
  99. {pymetamodel-0.5.3 → pymetamodel-0.6.1}/scripts/release +0 -0
  100. {pymetamodel-0.5.3 → pymetamodel-0.6.1}/scripts/test +0 -0
  101. {pymetamodel-0.5.3 → pymetamodel-0.6.1}/tests/__init__.py +0 -0
  102. {pymetamodel-0.5.3 → pymetamodel-0.6.1}/tests/basemwtest.py +0 -0
  103. {pymetamodel-0.5.3 → pymetamodel-0.6.1}/tests/basesmwtest.py +0 -0
  104. {pymetamodel-0.5.3 → pymetamodel-0.6.1}/tests/basetest.py +0 -0
  105. {pymetamodel-0.5.3 → pymetamodel-0.6.1}/tests/test_generators.py +0 -0
  106. {pymetamodel-0.5.3 → pymetamodel-0.6.1}/tests/test_plantuml.py +0 -0
  107. {pymetamodel-0.5.3 → pymetamodel-0.6.1}/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.1
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.1"
@@ -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
21
 
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
-
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,32 @@ 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
+ icon: Optional[str] = None
359
+ context: Optional[str] = None
360
+ _pluralName: Optional[str] = None
361
+ documentation: Optional[str] = None
362
+ wikiDocumentation: Optional[str] = None
363
+ defaultstoremode: str = "property"
364
+ extends: Optional[str] = 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)
369
+ # object references
370
+ context_obj: Optional[Context] = None
371
+ conceptProperty: Optional['Property'] = None
377
372
 
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
373
 
389
374
  def get_extends_topics(self, l: List['Topic'] = None) -> List['Topic']:
390
375
  """
@@ -441,6 +426,7 @@ class Topic(MetaModelElement):
441
426
  self.wikiDocumentation=doc
442
427
  if not hasattr(self,"defaultstoremode"):
443
428
  self.defaultstoremode="property"
429
+ pass
444
430
 
445
431
  @classmethod
446
432
  def getSamples(cls):
@@ -570,7 +556,7 @@ class Topic(MetaModelElement):
570
556
  props_count = len(props)
571
557
 
572
558
  # Sort properties locally by index
573
- sorted_props = sorted(props, key=lambda p: getattr(p, 'index', props_count))
559
+ sorted_props = sorted(props, key=lambda p: p.index or props_count)
574
560
 
575
561
  return sorted_props
576
562
 
@@ -638,16 +624,26 @@ class Topic(MetaModelElement):
638
624
  markup += f"""{self.askSort()}}}}}"""
639
625
  return markup
640
626
 
641
- class Property(MetaModelElement):
627
+ @lod_storable
628
+ class Property:
642
629
  """
643
630
  Provides helper functions and constants for properties
644
631
  """
632
+ name: Optional[str] = None
633
+ label: Optional[str] = None
634
+ type: Optional[str] = None
635
+ topic: Optional[str] = None
636
+ documentation: Optional[str] = None
637
+ namespace: str = "Property"
638
+ showInGrid: bool = True
639
+ isLink: bool = False
640
+ topicLink: Optional['TopicLink'] = None
641
+ index: Optional[int] = None
642
+ sortPos: Optional[int] = None
643
+ primaryKey: bool = False
644
+ mandatory: bool = False
645
+ sortAscending: bool = True
645
646
 
646
- def __init__(self):
647
- """
648
- constructor
649
- """
650
- MetaModelElement.__init__(self)
651
647
 
652
648
  @classmethod
653
649
  def getSamples(cls):
@@ -702,11 +698,24 @@ class Property(MetaModelElement):
702
698
  self.showInGrid=True
703
699
  pass
704
700
 
705
- class TopicLink(MetaModelElement):
701
+ @lod_storable
702
+ class TopicLink:
706
703
  """
707
704
  A TopicLink links two Concepts/Topics
708
705
  """
709
706
 
707
+ name: Optional[str] = None
708
+ source: Optional[str] = None
709
+ target: Optional[str] = None
710
+ sourceRole: Optional[str] = None
711
+ targetRole: Optional[str] = None
712
+ sourceMultiple: bool = False
713
+ targetMultiple: bool = False
714
+ sourceDocumentation: Optional[str] = None
715
+ targetDocumentation: Optional[str] = None
716
+ sourceTopic: Optional[Topic] = None
717
+ targetTopic: Optional[Topic] = None
718
+
710
719
  @classmethod
711
720
  def getSamples(cls):
712
721
  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 {
@@ -16,7 +16,7 @@ class Version(object):
16
16
  description = "pyMetaModel: MetaModel for Knowledge Graphs"
17
17
  version = meta.__version__
18
18
  date = "2022-11-30"
19
- updated = "2025-05-12"
19
+ updated = "2025-08-20"
20
20
  authors = "Wolfgang Fahl"
21
21
  doc_url = "https://wiki.bitplan.com/index.php/pyMetaModel"
22
22
  chat_url = "https://github.com/WolfgangFahl/pyMetaModel/discussions"
@@ -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