Skip to content

Commit 8948566

Browse files
authored
Merge pull request #64 from OpenSemanticLab/add-support-for-characteristics
Add basic support for characteristics
2 parents 56b2b46 + ea5012e commit 8948566

File tree

3 files changed

+140
-22
lines changed

3 files changed

+140
-22
lines changed

src/osw/core.py

Lines changed: 41 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -356,20 +356,26 @@ def _fetch_schema(self, fetchSchemaParam: _FetchSchemaParam = None) -> None:
356356
if not page.exists:
357357
print(f"Error: Page {schema_title} does not exist")
358358
return
359-
if schema_title.startswith("Category:"):
359+
# not only in the JsonSchema namespace the schema is located in the main sot
360+
# in all other namespaces, the json_schema slot is used
361+
if schema_title.startswith("JsonSchema:"):
362+
schema_str = ""
363+
if page.get_slot_content("main"):
364+
schema_str = json.dumps(page.get_slot_content("main"))
365+
else:
360366
schema_str = ""
361367
if page.get_slot_content("jsonschema"):
362368
schema_str = json.dumps(page.get_slot_content("jsonschema"))
363-
else:
364-
schema_str = page.get_slot_content("main")
365-
if schema_str and not isinstance(schema_str, str):
366-
schema_str = json.dumps(schema_str)
367369
if (schema_str is None) or (schema_str == ""):
368370
print(f"Error: Schema {schema_title} does not exist")
369-
return
371+
schema_str = "{}" # empty schema to make reference work
370372
schema = json.loads(
371-
schema_str.replace("$ref", "dollarref")
372-
) # '$' is a special char for root object in jsonpath
373+
schema_str.replace(
374+
"$ref", "dollarref"
375+
).replace( # '$' is a special char for root object in jsonpath
376+
'"allOf": [', '"allOf": [{},'
377+
) # fix https://github.com/koxudaxi/datamodel-code-generator/issues/1910
378+
)
373379
print(f"Fetch {schema_title}")
374380

375381
jsonpath_expr = parse("$..dollarref")
@@ -626,15 +632,15 @@ def load_entity(
626632
print("Error: no schema defined")
627633

628634
elif len(schemas) == 1:
629-
cls = schemas[0]["title"]
630-
entity: model.Entity = eval(f"model.{cls}(**jsondata)")
635+
cls = getattr(model, schemas[0]["title"])
636+
entity: model.Entity = cls(**jsondata)
631637

632638
else:
633639
bases = []
634640
for schema in schemas:
635-
bases.append(eval("model." + schema["title"]))
641+
bases.append(getattr(model, schema["title"]))
636642
cls = create_model("Test", __base__=tuple(bases))
637-
entity = cls(**jsondata)
643+
entity: model.Entity = cls(**jsondata)
638644

639645
if entity is not None:
640646
# make sure we do not override existing meta data
@@ -957,6 +963,8 @@ def store_entity(
957963
if not isinstance(param.entities, list):
958964
param.entities = [param.entities]
959965

966+
param: OSW.StoreEntityParam = param
967+
960968
max_index = len(param.entities)
961969

962970
meta_category = self.site.get_page(
@@ -970,12 +978,12 @@ def store_entity(
970978
meta_category = self.site.get_page(
971979
WtSite.GetPageParam(titles=[param.meta_category_title])
972980
).pages[0]
973-
param.meta_category_template_str = meta_category.get_slot_content(
981+
meta_category_template_str = meta_category.get_slot_content(
974982
"schema_template"
975983
)
976-
if param.meta_category_template_str:
984+
if meta_category_template_str:
977985
meta_category_template = compile_handlebars_template(
978-
param.meta_category_template_str
986+
meta_category_template_str
979987
)
980988

981989
def store_entity_(
@@ -1010,10 +1018,26 @@ def store_entity_(
10101018
schema_str = eval_compiled_handlebars_template(
10111019
meta_category_template,
10121020
page.get_slot_content("jsondata"),
1013-
{"_page_title": entity_title},
1021+
{
1022+
"_page_title": entity_title, # legacy
1023+
"_current_subject_": entity_title,
1024+
},
10141025
)
10151026
schema = json.loads(schema_str)
1016-
page.set_slot_content("jsonschema", schema)
1027+
# put generated schema in definitions section
1028+
# currently only enabled for Characteristics
1029+
if hasattr(model, "MetaCharacteristic") and isinstance(
1030+
entity, model.MetaCharacteristic
1031+
):
1032+
new_schema = {
1033+
"$defs": {"generated": schema},
1034+
"allOf": [{"$ref": "#/$defs/generated"}],
1035+
}
1036+
new_schema["@context"] = schema.pop("@context", None)
1037+
new_schema["title"] = schema.pop("title", "")
1038+
schema["title"] = "Generated" + new_schema["title"]
1039+
schema = new_schema
1040+
page.set_slot_content("jsonschema", new_schema)
10171041
except Exception as e:
10181042
print(
10191043
f"Schema generation from template failed for " f"{entity}: {e}"

src/osw/utils/wiki.py

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
1-
from typing import Union
1+
from typing import Type, Union
22
from uuid import UUID
33

44
import osw.model.entity as model
5+
from osw.model.static import OswBaseModel
56

67

78
def get_osw_id(uuid: UUID) -> str:
@@ -35,7 +36,7 @@ def get_uuid(osw_id) -> UUID:
3536
return UUID(osw_id.replace("OSW", ""))
3637

3738

38-
def get_namespace(entity: model.Entity) -> Union[str, None]:
39+
def get_namespace(entity: Union[OswBaseModel, Type[OswBaseModel]]) -> Union[str, None]:
3940
"""determines the wiki namespace based on the entity's type/class
4041
4142
Parameters
@@ -54,6 +55,7 @@ def get_namespace(entity: model.Entity) -> Union[str, None]:
5455
namespace = entity.meta.wiki_page.namespace
5556

5657
# (model classes may not exist => try except)
58+
# note: this may not work properly with dynamic reloaded model module
5759
if namespace is None:
5860
try:
5961
if issubclass(entity, model.Entity):
@@ -62,14 +64,20 @@ def get_namespace(entity: model.Entity) -> Union[str, None]:
6264
pass
6365
if namespace is None:
6466
try:
65-
if isinstance(entity, model.Item):
66-
namespace = "Item"
67+
if isinstance(entity, model.Category):
68+
namespace = "Category"
6769
except AttributeError:
6870
pass
6971
if namespace is None:
7072
try:
71-
if isinstance(entity, model.Category):
73+
if issubclass(entity, model.Characteristic):
7274
namespace = "Category"
75+
except (TypeError, AttributeError):
76+
pass
77+
if namespace is None:
78+
try:
79+
if isinstance(entity, model.Item):
80+
namespace = "Item"
7381
except AttributeError:
7482
pass
7583
if namespace is None:

tests/integration/store_and_load_test.py

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,3 +171,89 @@ def test_statement_creation(wiki_domain, wiki_username, wiki_password):
171171
assert f"Item:{OSW.get_osw_id(my_entity.uuid)}" in full_page_titles
172172

173173
osw.delete_entity(my_entity)
174+
175+
176+
def test_characteristic_creation(wiki_domain, wiki_username, wiki_password):
177+
cm = CredentialManager()
178+
cm.add_credential(
179+
CredentialManager.UserPwdCredential(
180+
iri=wiki_domain, username=wiki_username, password=wiki_password
181+
)
182+
)
183+
wtsite = WtSite(WtSite.WtSiteConfig(iri=wiki_domain, cred_mngr=cm))
184+
osw = OSW(site=wtsite)
185+
186+
osw.fetch_schema(
187+
OSW.FetchSchemaParam(
188+
schema_title=[
189+
"Category:OSWffe74f291d354037b318c422591c5023", # MetaCharacteristic
190+
"Category:Property",
191+
],
192+
mode="replace",
193+
)
194+
)
195+
196+
# my_property = model.Property
197+
198+
# Create a characteristic as instance of MetaCharacteristic
199+
my_characteristic = model.MetaCharacteristic(
200+
uuid="efad8086-4a76-47ca-b278-f5f944e5754b",
201+
name="TestCharacteristic",
202+
label=[model.Label(text="Test Characteristic")],
203+
properties=[
204+
model.PrimitiveProperty(
205+
uuid="766e7171-a183-4f9c-a9af-28cfd27fb1d9",
206+
name="test_property",
207+
type="string",
208+
property_type="SimpleProperty",
209+
),
210+
model.PrimitiveProperty(
211+
uuid="766e7171-a183-4f9c-a9af-28cfd27fb1d1",
212+
name="test_property2",
213+
rdf_property="Property:TestPropertyWithSchema",
214+
property_type="SimpleProperty",
215+
),
216+
],
217+
)
218+
219+
# store it as instance, which generates the schema
220+
# note: namespace and meta_category should be detected automatically in the future
221+
osw.store_entity(
222+
OSW.StoreEntityParam(
223+
entities=[my_characteristic],
224+
namespace="Category",
225+
meta_category_title="Category:OSWffe74f291d354037b318c422591c5023",
226+
overwrite=OverwriteOptions.true,
227+
)
228+
)
229+
230+
pages = osw.site.get_page(
231+
WtSite.GetPageParam(titles=["Property:TestPropertyWithSchema"])
232+
).pages
233+
pp = pages[0]
234+
# schema: dict = pp.get_slot_content("jsonschema")
235+
new_schema = {"type": "number", "description": "Imported from property schema"}
236+
pp.set_slot_content("jsonschema", new_schema)
237+
pp.edit()
238+
239+
# load the characteristic as category
240+
osw.fetch_schema(
241+
OSW.FetchSchemaParam(
242+
schema_title=[
243+
"Category:OSWefad80864a7647cab278f5f944e5754b" # TestCharacteristic
244+
],
245+
mode="append",
246+
)
247+
)
248+
249+
# create an instance of the characteristic
250+
t = model.TestCharacteristic(test_property="Test", test_property2=1)
251+
assert t.test_property == "Test"
252+
assert t.test_property2 == 1
253+
254+
# cleanup (disabled for paralle test matrix)
255+
# my_characteristic.meta = model.Meta(
256+
# wiki_page=model.WikiPage(namespace="Category")
257+
# ) # namespace detection fails otherwise
258+
# osw.delete_entity(my_characteristic)
259+
# pp.delete()

0 commit comments

Comments
 (0)