pyMetaModel 0.5.2__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.2 → pymetamodel-0.6.0}/.github/workflows/build.yml +4 -2
  2. {pymetamodel-0.5.2 → pymetamodel-0.6.0}/PKG-INFO +4 -6
  3. pymetamodel-0.6.0/meta/__init__.py +1 -0
  4. {pymetamodel-0.5.2 → pymetamodel-0.6.0}/meta/metamodel.py +123 -115
  5. {pymetamodel-0.5.2 → pymetamodel-0.6.0}/meta/metamodel_cmd.py +1 -1
  6. {pymetamodel-0.5.2 → pymetamodel-0.6.0}/meta/mw.py +4 -2
  7. {pymetamodel-0.5.2 → pymetamodel-0.6.0}/meta/sidif2linkml.py +4 -1
  8. {pymetamodel-0.5.2 → pymetamodel-0.6.0}/meta/smw_type.py +3 -19
  9. {pymetamodel-0.5.2 → pymetamodel-0.6.0}/meta/uml.py +1 -1
  10. {pymetamodel-0.5.2 → pymetamodel-0.6.0}/pyproject.toml +11 -14
  11. {pymetamodel-0.5.2 → pymetamodel-0.6.0}/tests/test_linkml.py +1 -1
  12. {pymetamodel-0.5.2 → pymetamodel-0.6.0}/tests/test_metamodel.py +4 -4
  13. {pymetamodel-0.5.2 → pymetamodel-0.6.0}/tests/test_mw.py +10 -6
  14. {pymetamodel-0.5.2 → pymetamodel-0.6.0}/tests/test_sidif.py +9 -3
  15. pymetamodel-0.5.2/meta/__init__.py +0 -1
  16. {pymetamodel-0.5.2 → pymetamodel-0.6.0}/.github/workflows/upload-to-pypi.yml +0 -0
  17. {pymetamodel-0.5.2 → pymetamodel-0.6.0}/.gitignore +0 -0
  18. {pymetamodel-0.5.2 → pymetamodel-0.6.0}/.project +0 -0
  19. {pymetamodel-0.5.2 → pymetamodel-0.6.0}/.pydevproject +0 -0
  20. {pymetamodel-0.5.2 → pymetamodel-0.6.0}/LICENSE +0 -0
  21. {pymetamodel-0.5.2 → pymetamodel-0.6.0}/README.md +0 -0
  22. {pymetamodel-0.5.2 → pymetamodel-0.6.0}/docs/index.md +0 -0
  23. {pymetamodel-0.5.2 → pymetamodel-0.6.0}/examples/ceur-ws/ceur-ws.mermaid +0 -0
  24. {pymetamodel-0.5.2 → pymetamodel-0.6.0}/examples/ceur-ws/ceur-ws.puml +0 -0
  25. {pymetamodel-0.5.2 → pymetamodel-0.6.0}/examples/ceur-ws/ceur-ws.py +0 -0
  26. {pymetamodel-0.5.2 → pymetamodel-0.6.0}/examples/ceur-ws/ceur-ws.sidif +0 -0
  27. {pymetamodel-0.5.2 → pymetamodel-0.6.0}/examples/ceur-ws/ceur-ws.xlsx +0 -0
  28. {pymetamodel-0.5.2 → pymetamodel-0.6.0}/examples/ceur-ws/ceur-ws.yaml +0 -0
  29. {pymetamodel-0.5.2 → pymetamodel-0.6.0}/examples/ceur-ws/ceur-ws_puml.txt +0 -0
  30. {pymetamodel-0.5.2 → pymetamodel-0.6.0}/examples/city/city.mermaid +0 -0
  31. {pymetamodel-0.5.2 → pymetamodel-0.6.0}/examples/city/city.puml +0 -0
  32. {pymetamodel-0.5.2 → pymetamodel-0.6.0}/examples/city/city.py +0 -0
  33. {pymetamodel-0.5.2 → pymetamodel-0.6.0}/examples/city/city.sidif +0 -0
  34. {pymetamodel-0.5.2 → pymetamodel-0.6.0}/examples/city/city.xlsx +0 -0
  35. {pymetamodel-0.5.2 → pymetamodel-0.6.0}/examples/city/city.yaml +0 -0
  36. {pymetamodel-0.5.2 → pymetamodel-0.6.0}/examples/city/city_puml.txt +0 -0
  37. {pymetamodel-0.5.2 → pymetamodel-0.6.0}/examples/family/FamilyContext.mermaid +0 -0
  38. {pymetamodel-0.5.2 → pymetamodel-0.6.0}/examples/family/FamilyContext.puml +0 -0
  39. {pymetamodel-0.5.2 → pymetamodel-0.6.0}/examples/family/FamilyContext.py +0 -0
  40. {pymetamodel-0.5.2 → pymetamodel-0.6.0}/examples/family/FamilyContext.sidif +0 -0
  41. {pymetamodel-0.5.2 → pymetamodel-0.6.0}/examples/family/FamilyContext.xlsx +0 -0
  42. {pymetamodel-0.5.2 → pymetamodel-0.6.0}/examples/family/FamilyContext.yaml +0 -0
  43. {pymetamodel-0.5.2 → pymetamodel-0.6.0}/examples/family/FamilyContext_puml.txt +0 -0
  44. {pymetamodel-0.5.2 → pymetamodel-0.6.0}/examples/infrastructure/infrastructure.mermaid +0 -0
  45. {pymetamodel-0.5.2 → pymetamodel-0.6.0}/examples/infrastructure/infrastructure.puml +0 -0
  46. {pymetamodel-0.5.2 → pymetamodel-0.6.0}/examples/infrastructure/infrastructure.py +0 -0
  47. {pymetamodel-0.5.2 → pymetamodel-0.6.0}/examples/infrastructure/infrastructure.sidif +0 -0
  48. {pymetamodel-0.5.2 → pymetamodel-0.6.0}/examples/infrastructure/infrastructure.xlsx +0 -0
  49. {pymetamodel-0.5.2 → pymetamodel-0.6.0}/examples/infrastructure/infrastructure.yaml +0 -0
  50. {pymetamodel-0.5.2 → pymetamodel-0.6.0}/examples/infrastructure/infrastructure_puml.txt +0 -0
  51. {pymetamodel-0.5.2 → pymetamodel-0.6.0}/examples/metamodel/metamodel.mermaid +0 -0
  52. {pymetamodel-0.5.2 → pymetamodel-0.6.0}/examples/metamodel/metamodel.puml +0 -0
  53. {pymetamodel-0.5.2 → pymetamodel-0.6.0}/examples/metamodel/metamodel.py +0 -0
  54. {pymetamodel-0.5.2 → pymetamodel-0.6.0}/examples/metamodel/metamodel.sidif +0 -0
  55. {pymetamodel-0.5.2 → pymetamodel-0.6.0}/examples/metamodel/metamodel.xlsx +0 -0
  56. {pymetamodel-0.5.2 → pymetamodel-0.6.0}/examples/metamodel/metamodel.yaml +0 -0
  57. {pymetamodel-0.5.2 → pymetamodel-0.6.0}/examples/metamodel/metamodel_puml.txt +0 -0
  58. {pymetamodel-0.5.2 → pymetamodel-0.6.0}/examples/scientific-events/scientific-events.mermaid +0 -0
  59. {pymetamodel-0.5.2 → pymetamodel-0.6.0}/examples/scientific-events/scientific-events.puml +0 -0
  60. {pymetamodel-0.5.2 → pymetamodel-0.6.0}/examples/scientific-events/scientific-events.py +0 -0
  61. {pymetamodel-0.5.2 → pymetamodel-0.6.0}/examples/scientific-events/scientific-events.sidif +0 -0
  62. {pymetamodel-0.5.2 → pymetamodel-0.6.0}/examples/scientific-events/scientific-events.xlsx +0 -0
  63. {pymetamodel-0.5.2 → pymetamodel-0.6.0}/examples/scientific-events/scientific-events.yaml +0 -0
  64. {pymetamodel-0.5.2 → pymetamodel-0.6.0}/examples/scientific-events/scientific-events_puml.txt +0 -0
  65. {pymetamodel-0.5.2 → pymetamodel-0.6.0}/examples/smartRQM/smartRQM.mermaid +0 -0
  66. {pymetamodel-0.5.2 → pymetamodel-0.6.0}/examples/smartRQM/smartRQM.puml +0 -0
  67. {pymetamodel-0.5.2 → pymetamodel-0.6.0}/examples/smartRQM/smartRQM.py +0 -0
  68. {pymetamodel-0.5.2 → pymetamodel-0.6.0}/examples/smartRQM/smartRQM.sidif +0 -0
  69. {pymetamodel-0.5.2 → pymetamodel-0.6.0}/examples/smartRQM/smartRQM.yaml +0 -0
  70. {pymetamodel-0.5.2 → pymetamodel-0.6.0}/examples/smartRQM/smartRQM_puml.txt +0 -0
  71. {pymetamodel-0.5.2 → pymetamodel-0.6.0}/examples/smwcon/smwcon.mermaid +0 -0
  72. {pymetamodel-0.5.2 → pymetamodel-0.6.0}/examples/smwcon/smwcon.puml +0 -0
  73. {pymetamodel-0.5.2 → pymetamodel-0.6.0}/examples/smwcon/smwcon.py +0 -0
  74. {pymetamodel-0.5.2 → pymetamodel-0.6.0}/examples/smwcon/smwcon.sidif +0 -0
  75. {pymetamodel-0.5.2 → pymetamodel-0.6.0}/examples/smwcon/smwcon.xlsx +0 -0
  76. {pymetamodel-0.5.2 → pymetamodel-0.6.0}/examples/smwcon/smwcon.yaml +0 -0
  77. {pymetamodel-0.5.2 → pymetamodel-0.6.0}/examples/smwcon/smwcon_puml.txt +0 -0
  78. {pymetamodel-0.5.2 → pymetamodel-0.6.0}/examples/teaching/TeachingSchema.mermaid +0 -0
  79. {pymetamodel-0.5.2 → pymetamodel-0.6.0}/examples/teaching/TeachingSchema.puml +0 -0
  80. {pymetamodel-0.5.2 → pymetamodel-0.6.0}/examples/teaching/TeachingSchema.py +0 -0
  81. {pymetamodel-0.5.2 → pymetamodel-0.6.0}/examples/teaching/TeachingSchema.sidif +0 -0
  82. {pymetamodel-0.5.2 → pymetamodel-0.6.0}/examples/teaching/TeachingSchema.xlsx +0 -0
  83. {pymetamodel-0.5.2 → pymetamodel-0.6.0}/examples/teaching/TeachingSchema.yaml +0 -0
  84. {pymetamodel-0.5.2 → pymetamodel-0.6.0}/examples/teaching/TeachingSchema_puml.txt +0 -0
  85. {pymetamodel-0.5.2 → pymetamodel-0.6.0}/examples/wiki/wiki.mermaid +0 -0
  86. {pymetamodel-0.5.2 → pymetamodel-0.6.0}/examples/wiki/wiki.puml +0 -0
  87. {pymetamodel-0.5.2 → pymetamodel-0.6.0}/examples/wiki/wiki.py +0 -0
  88. {pymetamodel-0.5.2 → pymetamodel-0.6.0}/examples/wiki/wiki.sidif +0 -0
  89. {pymetamodel-0.5.2 → pymetamodel-0.6.0}/examples/wiki/wiki.xlsx +0 -0
  90. {pymetamodel-0.5.2 → pymetamodel-0.6.0}/examples/wiki/wiki.yaml +0 -0
  91. {pymetamodel-0.5.2 → pymetamodel-0.6.0}/examples/wiki/wiki_puml.txt +0 -0
  92. {pymetamodel-0.5.2 → pymetamodel-0.6.0}/meta/profiler.py +0 -0
  93. {pymetamodel-0.5.2 → pymetamodel-0.6.0}/meta/version.py +0 -0
  94. {pymetamodel-0.5.2 → pymetamodel-0.6.0}/metamodel.puml +0 -0
  95. {pymetamodel-0.5.2 → pymetamodel-0.6.0}/mkdocs.yml +0 -0
  96. {pymetamodel-0.5.2 → pymetamodel-0.6.0}/scripts/blackisort +0 -0
  97. {pymetamodel-0.5.2 → pymetamodel-0.6.0}/scripts/doc +0 -0
  98. {pymetamodel-0.5.2 → pymetamodel-0.6.0}/scripts/genexamples +0 -0
  99. {pymetamodel-0.5.2 → pymetamodel-0.6.0}/scripts/install +0 -0
  100. {pymetamodel-0.5.2 → pymetamodel-0.6.0}/scripts/release +0 -0
  101. {pymetamodel-0.5.2 → pymetamodel-0.6.0}/scripts/test +0 -0
  102. {pymetamodel-0.5.2 → pymetamodel-0.6.0}/tests/__init__.py +0 -0
  103. {pymetamodel-0.5.2 → pymetamodel-0.6.0}/tests/basemwtest.py +0 -0
  104. {pymetamodel-0.5.2 → pymetamodel-0.6.0}/tests/basesmwtest.py +0 -0
  105. {pymetamodel-0.5.2 → pymetamodel-0.6.0}/tests/basetest.py +0 -0
  106. {pymetamodel-0.5.2 → pymetamodel-0.6.0}/tests/test_generators.py +0 -0
  107. {pymetamodel-0.5.2 → pymetamodel-0.6.0}/tests/test_plantuml.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.2
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
  }
@@ -210,6 +184,7 @@ class Context(MetaModelElement):
210
184
  prop.type = "Page"
211
185
  prop.topicLink = tl
212
186
  prop.isLink = True
187
+ prop.showInGrid = False
213
188
  return prop
214
189
 
215
190
  @classmethod
@@ -225,51 +200,53 @@ class Context(MetaModelElement):
225
200
  """
226
201
  context = None
227
202
  for key, record in did.items():
228
- isA = record.get("isA")
229
- if isA == "Context":
230
- context = Context()
231
- context.fromDict(record)
232
- context.sanitize(key)
233
- elif isA == "TopicLink":
234
- """
235
- # Event n : 1 City
236
- Event_in_City isA TopicLink
237
- "eventInCity" is name of it
238
- "city" is sourceRole of it
239
- false is sourceMultiple of it
240
- "City" is source of it
241
- "event" is targetRole of it
242
- true is targetMultiple of it
243
- "Event" is target of it
244
- """
245
- tl = TopicLink()
246
- tl.fromDict(record)
247
- context.addLink(tl)
248
- elif isA == "Property":
249
- prop = Property()
250
- prop.isLink = False
251
- prop.fromDict(record)
252
- prop.sanitize()
253
- context.addProperty(prop)
254
- else: # isA == Topic or in declared topics
255
- topic = Topic()
256
- topic.fromDict(record)
257
- topic.sanitize()
258
- if context is None:
259
- context = Context()
260
- context.name = "GlobalContext"
261
- context.since = "2022-11-26"
262
- context.master = "http://contexts.bitplan.com"
263
- context.error(f"topic {topic.name} has no defined context")
264
- if hasattr(topic, "name"):
265
- context.topics[topic.name] = topic
266
- topic.context_obj=context
267
- elif hasattr(topic, "type"):
268
- 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)
269
248
  else:
270
- # potential foreign or extends declaration
271
- context.error(f"missing name for topic {topic} {key} - foreign declaration?")
272
-
249
+ raise ex
273
250
  # link topic to concepts and add topicLinks
274
251
  for topic in context.topics.values():
275
252
  topic.setConceptProperty()
@@ -355,8 +332,9 @@ class Context(MetaModelElement):
355
332
  error = None
356
333
  errMsg = None
357
334
  sidif = None
335
+ msg=f"reading sidif for {mw_context.context} from {mw_context.wikiId}"
358
336
  if debug:
359
- print(f"reading sidif for {mw_context.context} from {mw_context.wikiId}")
337
+ print(msg)
360
338
  try:
361
339
  sidif = mw_context.read_sidif()
362
340
  except BaseException as ex:
@@ -366,24 +344,29 @@ class Context(MetaModelElement):
366
344
  context, error, errMsg = cls.fromSiDIF(
367
345
  sidif=sidif, title=mw_context.wikiId, depth=depth, debug=debug
368
346
  )
347
+ else:
348
+ errMsg=f"{msg} failed"
349
+ error=ValueError(msg)
369
350
  return context, error, errMsg
370
351
 
371
-
372
- class Topic(MetaModelElement):
352
+ @lod_storable
353
+ class Topic:
373
354
  """
374
355
  A Topic is a Concept/Class/Thing/Entity
375
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)
376
369
 
377
- def __init__(self):
378
- """
379
- constructor
380
- """
381
- MetaModelElement.__init__(self)
382
- self._pluralName = None # Initialize with underscore to indicate a protected attribute
383
-
384
- self.properties = {}
385
- self.sourceTopicLinks = {}
386
- self.targetTopicLinks = {}
387
370
 
388
371
  def get_extends_topics(self, l: List['Topic'] = None) -> List['Topic']:
389
372
  """
@@ -569,7 +552,7 @@ class Topic(MetaModelElement):
569
552
  props_count = len(props)
570
553
 
571
554
  # Sort properties locally by index
572
- 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)
573
556
 
574
557
  return sorted_props
575
558
 
@@ -637,16 +620,26 @@ class Topic(MetaModelElement):
637
620
  markup += f"""{self.askSort()}}}}}"""
638
621
  return markup
639
622
 
640
- class Property(MetaModelElement):
623
+ @lod_storable
624
+ class Property:
641
625
  """
642
626
  Provides helper functions and constants for properties
643
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
644
642
 
645
- def __init__(self):
646
- """
647
- constructor
648
- """
649
- MetaModelElement.__init__(self)
650
643
 
651
644
  @classmethod
652
645
  def getSamples(cls):
@@ -697,13 +690,28 @@ class Property(MetaModelElement):
697
690
  self.topicLink=None
698
691
  if hasattr(self, "scope"):
699
692
  pass
693
+ if not hasattr(self, "showInGrid"):
694
+ self.showInGrid=True
700
695
  pass
701
696
 
702
- class TopicLink(MetaModelElement):
697
+ @lod_storable
698
+ class TopicLink:
703
699
  """
704
700
  A TopicLink links two Concepts/Topics
705
701
  """
706
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
+
707
715
  @classmethod
708
716
  def getSamples(cls):
709
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)
@@ -18,6 +18,9 @@ class TestSiDIF(Basetest):
18
18
 
19
19
 
20
20
  def check_sidif(self,sidif_path,file)->Context:
21
+ """
22
+ check the given SiDIF input
23
+ """
21
24
  debug=self.debug
22
25
  context, error, errMsg = Context.fromSiDIF_input(sidif_path, debug=debug)
23
26
  self.assertFalse(error, f"Error in {file}: {errMsg}")
@@ -38,9 +41,12 @@ class TestSiDIF(Basetest):
38
41
 
39
42
  # Check if all properties have names and types
40
43
  for topic in context.topics.values():
41
- for prop in topic.properties.values():
42
- self.assertTrue(hasattr(prop, 'name'), f"Property without name in {file}")
43
- self.assertTrue(hasattr(prop, 'type'), f"Property without type in {file}")
44
+ for key, prop in topic.properties.items():
45
+ for needed_prop in ["name", "type", "showInGrid"]:
46
+ self.assertTrue(
47
+ hasattr(prop, needed_prop),
48
+ f"Property '{key}' missing attribute '{needed_prop}' in {file}"
49
+ )
44
50
  return context
45
51
 
46
52
 
@@ -1 +0,0 @@
1
- __version__ = "0.5.2"
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