-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Update to work with new array schema and LoL pydantic generator (#14)
- Loading branch information
Showing
71 changed files
with
2,042 additions
and
3,806 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,49 +1,50 @@ | ||
[tool.poetry] | ||
name = "linkml-arrays" | ||
version = "0.0.0" | ||
version = "0.1.0" | ||
description = "linkml-arrays" | ||
authors = ["Ryan Ly <[email protected]>"] | ||
authors = [ | ||
"Ryan Ly <[email protected]>", | ||
"Chris Mungall <[email protected]>", | ||
] | ||
license = "BSD-3" | ||
readme = "README.md" | ||
|
||
[tool.poetry.dependencies] | ||
python = "^3.9" | ||
linkml-runtime = ">=1.7.0" | ||
linkml-runtime = ">=1.8.0" | ||
numpy = ">=1.24.3" | ||
h5py = ">=3.9.0" | ||
zarr = ">=2.16.1" | ||
nptyping = ">=2.5.0" | ||
xarray = "^2024.1.1" | ||
tox = "^3.25.1" # TODO move out of main deps | ||
ruamel-yaml = "^0.18.6" | ||
importlib_metadata = "*" | ||
|
||
[tool.poetry.dev-dependencies] | ||
pytest = "^7.1.2" | ||
sphinx = {version = "^5.3.0", extras = ["docs"]} | ||
sphinx-rtd-theme = {version = "^1.0.0", extras = ["docs"]} | ||
# sphinx-autodoc-typehints = {version = "^1.19.4", extras = ["docs"]} | ||
sphinx-click = {version = "^4.3.0", extras = ["docs"]} | ||
myst-parser = {version = "^0.18.1", extras = ["docs"]} | ||
jupyter = {version = "*", extras = ["jupyter"]} | ||
|
||
[tool.poetry.scripts] | ||
linkml-arrays = "linkml_arrays.cli:main" | ||
pytest = "*" | ||
tox = "*" | ||
# sphinx = {version = "*", extras = ["docs"]} | ||
# sphinx-rtd-theme = {version = "^1.0.0", extras = ["docs"]} | ||
# # sphinx-autodoc-typehints = {version = "^1.19.4", extras = ["docs"]} | ||
# sphinx-click = {version = "^4.3.0", extras = ["docs"]} | ||
# myst-parser = {version = "*", extras = ["docs"]} | ||
# jupyter = {version = "*", extras = ["jupyter"]} | ||
|
||
[tool.poetry.extras] | ||
docs = [ | ||
"sphinx", | ||
"sphinx-rtd-theme", | ||
# "sphinx-autodoc-typehints", | ||
"sphinx-click", | ||
"myst-parser" | ||
] | ||
jupyter = [ | ||
"jupyter" | ||
] | ||
# [tool.poetry.extras] | ||
# docs = [ | ||
# "sphinx", | ||
# "sphinx-rtd-theme", | ||
# "sphinx-autodoc-typehints", | ||
# "sphinx-click", | ||
# "myst-parser" | ||
# ] | ||
# jupyter = [ | ||
# "jupyter" | ||
# ] | ||
|
||
[tool.poetry.group.dev.dependencies] | ||
black = "^24.1.1" | ||
pytest = "^7.1.2" | ||
mypy = "^1.8.0" | ||
# [tool.poetry.group.dev.dependencies] | ||
# black = "^24.1.1" | ||
# pytest = "^7.1.2" | ||
# mypy = "^1.8.0" | ||
|
||
[tool.poetry-dynamic-versioning] | ||
enable = true | ||
|
@@ -52,7 +53,6 @@ style = "pep440" | |
|
||
[tool.black] | ||
line-length = 100 | ||
target-version = ["py38", "py39", "py310"] | ||
|
||
[tool.isort] | ||
profile = "black" | ||
|
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,123 @@ | ||
"""Base class for dumping a LinkML model to YAML with paths to files containing arrays.""" | ||
|
||
import os | ||
from abc import ABCMeta, abstractmethod | ||
from collections.abc import Callable | ||
from pathlib import Path | ||
from typing import List, Optional, Union | ||
|
||
import numpy as np | ||
import yaml | ||
from linkml_runtime import SchemaView | ||
from linkml_runtime.dumpers.dumper_root import Dumper | ||
from linkml_runtime.utils.yamlutils import YAMLRoot | ||
from pydantic import BaseModel | ||
|
||
|
||
def _iterate_element( | ||
element: Union[YAMLRoot, BaseModel], | ||
schemaview: SchemaView, | ||
output_dir: Path, | ||
write_array: Callable, | ||
format: str, | ||
parent_identifier=None, | ||
inlined_name=None, | ||
): | ||
"""Recursively iterate through the elements of a LinkML model and save them. | ||
Return a dictionary with the same structure as the input element, but where the slots | ||
with the "array" element are written to an array file and the paths to these | ||
files are returned in the dictionary. The paths are relative to the output directory. | ||
Raises: | ||
ValueError: If the class requires an identifier and it is not provided. | ||
""" | ||
# get the type of the element | ||
element_type = type(element).__name__ | ||
|
||
# ask schemaview whether it has a class by this name | ||
found_class = schemaview.get_class(element_type) | ||
|
||
id_slot = schemaview.get_identifier_slot(found_class.name) | ||
if id_slot is not None: | ||
id_value = getattr(element, id_slot.name) | ||
else: | ||
id_value = None | ||
|
||
ret_dict = dict() | ||
for k, v in vars(element).items(): | ||
found_slot = schemaview.induced_slot(k, element_type) | ||
if found_slot.array: | ||
if id_slot is None and parent_identifier is None: | ||
raise ValueError("The class requires an identifier.") | ||
|
||
# determine the output file name without the suffix | ||
if id_slot is not None: | ||
output_file_name = f"{id_value}.{found_slot.name}" | ||
elif inlined_name is not None: | ||
output_file_name = f"{parent_identifier}.{inlined_name}.{found_slot.name}" | ||
elif parent_identifier is not None: | ||
output_file_name = f"{parent_identifier}.{found_slot.name}" | ||
else: | ||
output_file_name = f"{found_slot.name}" | ||
|
||
# if output_dir is absolute, make it relative to current working directory | ||
# and create the directory if it does not exist | ||
if output_dir.is_absolute(): | ||
output_dir = Path(os.path.relpath(output_dir, start=os.getcwd())) | ||
output_dir.mkdir(exist_ok=True) | ||
output_file_path_no_suffix = output_dir / output_file_name | ||
|
||
# save the numpy array to file and write the file path to the dictionary | ||
output_file_path = write_array(v, output_file_path_no_suffix) | ||
ret_dict[k] = { | ||
"source": [ | ||
{ | ||
"file": f"./{output_file_path}", | ||
"format": format, | ||
} | ||
] | ||
} | ||
else: | ||
if isinstance(v, BaseModel): | ||
v2 = _iterate_element( | ||
v, | ||
schemaview, | ||
output_dir, | ||
write_array, | ||
format, | ||
id_value, | ||
inlined_name=found_slot.name, | ||
) | ||
ret_dict[k] = v2 | ||
else: | ||
ret_dict[k] = v | ||
return ret_dict | ||
|
||
|
||
class YamlArrayFileDumper(Dumper, metaclass=ABCMeta): | ||
"""Base dumper class for LinkML models to YAML files with paths to array files.""" | ||
|
||
# FORMAT is a class attribute that must be set by subclasses | ||
|
||
def dumps( | ||
self, | ||
element: Union[YAMLRoot, BaseModel], | ||
schemaview: SchemaView, | ||
output_dir: Optional[Union[str, Path]] = None, | ||
**kwargs, | ||
) -> str: | ||
"""Return element formatted as a YAML string.""" | ||
if output_dir is None: | ||
output_dir = "." | ||
input = _iterate_element( | ||
element, schemaview, Path(output_dir), self.write_array, self.FORMAT | ||
) | ||
|
||
return yaml.dump(input) | ||
|
||
@classmethod | ||
@abstractmethod | ||
def write_array(cls, array: Union[List, np.ndarray], output_file_path: Union[str, Path]): | ||
"""Write an array to a file.""" | ||
raise NotImplementedError("Subclasses must implement this method.") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.