mirror of
https://github.com/p2p-ld/nwb-linkml.git
synced 2024-11-10 00:34:29 +00:00
fix imports being inside the any_of range, more manual inspection before finishing for the night
This commit is contained in:
parent
781b667952
commit
af11bb61ec
4 changed files with 47 additions and 7 deletions
|
@ -11,6 +11,8 @@ NWB schema translation
|
||||||
Cleanup
|
Cleanup
|
||||||
- [ ] Update pydantic generator
|
- [ ] Update pydantic generator
|
||||||
- [ ] Restore regressions from stripping the generator
|
- [ ] Restore regressions from stripping the generator
|
||||||
|
- [x] Make any_of with array ranges work
|
||||||
|
- [ ] PR upstream `equals_string` and `ifabsent` (if existing PR doesnt fix)
|
||||||
- [ ] Use the class rather than a string in _get_class_slot_range_origin:
|
- [ ] Use the class rather than a string in _get_class_slot_range_origin:
|
||||||
```
|
```
|
||||||
or inlined_as_list
|
or inlined_as_list
|
||||||
|
@ -43,6 +45,9 @@ Important things that are not implemented yet!
|
||||||
Remove monkeypatches/overrides once PRs are closed
|
Remove monkeypatches/overrides once PRs are closed
|
||||||
- [ ] https://github.com/linkml/linkml-runtime/pull/330
|
- [ ] https://github.com/linkml/linkml-runtime/pull/330
|
||||||
|
|
||||||
|
Tests
|
||||||
|
- [ ] Ensure schemas and pydantic modules in repos are up to date
|
||||||
|
|
||||||
## Docs TODOs
|
## Docs TODOs
|
||||||
|
|
||||||
```{todolist}
|
```{todolist}
|
||||||
|
|
|
@ -246,7 +246,6 @@ class ClassAdapter(Adapter):
|
||||||
ifabsent=f"string({name})",
|
ifabsent=f"string({name})",
|
||||||
equals_string=equals_string,
|
equals_string=equals_string,
|
||||||
range="string",
|
range="string",
|
||||||
identifier=True,
|
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
name_slot = SlotDefinition(name="name", required=True, range="string", identifier=True)
|
name_slot = SlotDefinition(name="name", required=True, range="string", identifier=True)
|
||||||
|
|
|
@ -30,6 +30,7 @@ The `serialize` method:
|
||||||
|
|
||||||
import inspect
|
import inspect
|
||||||
import pdb
|
import pdb
|
||||||
|
import re
|
||||||
import sys
|
import sys
|
||||||
import warnings
|
import warnings
|
||||||
from copy import copy
|
from copy import copy
|
||||||
|
@ -40,7 +41,8 @@ from typing import ClassVar, Dict, List, Optional, Tuple, Type, Union
|
||||||
|
|
||||||
from linkml.generators import PydanticGenerator
|
from linkml.generators import PydanticGenerator
|
||||||
from linkml.generators.pydanticgen.build import SlotResult
|
from linkml.generators.pydanticgen.build import SlotResult
|
||||||
from linkml.generators.pydanticgen.array import ArrayRepresentation
|
from linkml.generators.pydanticgen.array import ArrayRepresentation, NumpydanticArray
|
||||||
|
from linkml.generators.pydanticgen.template import PydanticModule
|
||||||
from linkml_runtime.linkml_model.meta import (
|
from linkml_runtime.linkml_model.meta import (
|
||||||
Annotation,
|
Annotation,
|
||||||
AnonymousSlotExpression,
|
AnonymousSlotExpression,
|
||||||
|
@ -61,6 +63,8 @@ from pydantic import BaseModel
|
||||||
from nwb_linkml.maps import flat_to_nptyping
|
from nwb_linkml.maps import flat_to_nptyping
|
||||||
from nwb_linkml.maps.naming import module_case, version_module_case
|
from nwb_linkml.maps.naming import module_case, version_module_case
|
||||||
|
|
||||||
|
OPTIONAL_PATTERN = re.compile(r'Optional\[([\w\.]*)\]')
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class NWBPydanticGenerator(PydanticGenerator):
|
class NWBPydanticGenerator(PydanticGenerator):
|
||||||
|
|
||||||
|
@ -86,7 +90,7 @@ class NWBPydanticGenerator(PydanticGenerator):
|
||||||
gen_slots: bool = True
|
gen_slots: bool = True
|
||||||
|
|
||||||
|
|
||||||
skip_meta: ClassVar[Tuple[str]] = ('domain_of',)
|
skip_meta: ClassVar[Tuple[str]] = ('domain_of','alias')
|
||||||
|
|
||||||
def _check_anyof(
|
def _check_anyof(
|
||||||
self, s: SlotDefinition, sn: SlotDefinitionName, sv: SchemaView
|
self, s: SlotDefinition, sn: SlotDefinitionName, sv: SchemaView
|
||||||
|
@ -111,18 +115,42 @@ class NWBPydanticGenerator(PydanticGenerator):
|
||||||
if not base_range_subsumes_any_of:
|
if not base_range_subsumes_any_of:
|
||||||
raise ValueError("Slot cannot have both range and any_of defined")
|
raise ValueError("Slot cannot have both range and any_of defined")
|
||||||
|
|
||||||
def before_generate_schema(self):
|
|
||||||
pass
|
|
||||||
|
|
||||||
def after_generate_slot(self, slot: SlotResult, sv: SchemaView) -> SlotResult:
|
def after_generate_slot(self, slot: SlotResult, sv: SchemaView) -> SlotResult:
|
||||||
"""
|
"""
|
||||||
- strip unwanted metadata
|
- strip unwanted metadata
|
||||||
|
- generate range with any_of
|
||||||
"""
|
"""
|
||||||
for key in self.skip_meta:
|
for key in self.skip_meta:
|
||||||
if key in slot.attribute.meta:
|
if key in slot.attribute.meta:
|
||||||
del slot.attribute.meta[key]
|
del slot.attribute.meta[key]
|
||||||
|
|
||||||
|
# make array ranges in any_of
|
||||||
|
if 'any_of' in slot.attribute.meta:
|
||||||
|
any_ofs = slot.attribute.meta['any_of']
|
||||||
|
if all(['array' in expr for expr in any_ofs]):
|
||||||
|
ranges = []
|
||||||
|
is_optional = False
|
||||||
|
for expr in any_ofs:
|
||||||
|
# remove optional from inner type
|
||||||
|
pyrange = slot.attribute.range
|
||||||
|
is_optional = OPTIONAL_PATTERN.match(pyrange)
|
||||||
|
if is_optional:
|
||||||
|
pyrange = is_optional.groups()[0]
|
||||||
|
range_generator = NumpydanticArray(ArrayExpression(**expr['array']), pyrange)
|
||||||
|
ranges.append(range_generator.make().range)
|
||||||
|
|
||||||
|
slot.attribute.range = 'Union[' + ', '.join(ranges) + ']'
|
||||||
|
if is_optional:
|
||||||
|
slot.attribute.range = 'Optional[' + slot.attribute.range + ']'
|
||||||
|
del slot.attribute.meta['any_of']
|
||||||
|
|
||||||
return slot
|
return slot
|
||||||
|
|
||||||
|
def before_render_template(self, template: PydanticModule, sv: SchemaView) -> PydanticModule:
|
||||||
|
if 'source_file' in template.meta:
|
||||||
|
del template.meta['source_file']
|
||||||
|
|
||||||
|
|
||||||
def compile_module(
|
def compile_module(
|
||||||
self, module_path: Path = None, module_name: str = "test", **kwargs
|
self, module_path: Path = None, module_name: str = "test", **kwargs
|
||||||
) -> ModuleType: # pragma: no cover - replaced with provider
|
) -> ModuleType: # pragma: no cover - replaced with provider
|
||||||
|
|
|
@ -12,7 +12,7 @@ from types import ModuleType
|
||||||
from typing import List, Optional, Type
|
from typing import List, Optional, Type
|
||||||
|
|
||||||
from linkml_runtime.linkml_model.meta import SchemaDefinition
|
from linkml_runtime.linkml_model.meta import SchemaDefinition
|
||||||
from linkml.generators.pydanticgen.pydanticgen import SplitMode, _import_to_path
|
from linkml.generators.pydanticgen.pydanticgen import SplitMode, _import_to_path, _ensure_inits
|
||||||
from pydantic import BaseModel
|
from pydantic import BaseModel
|
||||||
|
|
||||||
from nwb_linkml.generators.pydantic import NWBPydanticGenerator
|
from nwb_linkml.generators.pydantic import NWBPydanticGenerator
|
||||||
|
@ -148,7 +148,9 @@ class PydanticProvider(Provider):
|
||||||
force: bool,
|
force: bool,
|
||||||
**kwargs
|
**kwargs
|
||||||
) -> List[str]:
|
) -> List[str]:
|
||||||
|
# FIXME: This is messy as all fuck, we're just getting it to work again so we can start iterating on the models themselves
|
||||||
res = []
|
res = []
|
||||||
|
module_paths = []
|
||||||
|
|
||||||
# first make the namespace file we were given
|
# first make the namespace file we were given
|
||||||
|
|
||||||
|
@ -170,6 +172,7 @@ class PydanticProvider(Provider):
|
||||||
if dump:
|
if dump:
|
||||||
with open(ns_file, 'w') as ofile:
|
with open(ns_file, 'w') as ofile:
|
||||||
ofile.write(serialized)
|
ofile.write(serialized)
|
||||||
|
module_paths.append(ns_file)
|
||||||
else:
|
else:
|
||||||
with open(ns_file, 'r') as ofile:
|
with open(ns_file, 'r') as ofile:
|
||||||
serialized = ofile.read()
|
serialized = ofile.read()
|
||||||
|
@ -203,6 +206,7 @@ class PydanticProvider(Provider):
|
||||||
if dump:
|
if dump:
|
||||||
with open(import_file, 'w') as ofile:
|
with open(import_file, 'w') as ofile:
|
||||||
ofile.write(serialized)
|
ofile.write(serialized)
|
||||||
|
module_paths.append(import_file)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
with open(import_file, 'r') as ofile:
|
with open(import_file, 'r') as ofile:
|
||||||
|
@ -210,6 +214,10 @@ class PydanticProvider(Provider):
|
||||||
|
|
||||||
res.append(serialized)
|
res.append(serialized)
|
||||||
|
|
||||||
|
# make __init__.py files if we generated any files
|
||||||
|
if len(module_paths) > 0:
|
||||||
|
_ensure_inits(module_paths)
|
||||||
|
|
||||||
return res
|
return res
|
||||||
|
|
||||||
def _make_inits(self, out_file: Path) -> None:
|
def _make_inits(self, out_file: Path) -> None:
|
||||||
|
|
Loading…
Reference in a new issue