Skip to content

Commit

Permalink
pulling in changes for schema update
Browse files Browse the repository at this point in the history
  • Loading branch information
duboyal committed Apr 24, 2024
2 parents 8984488 + ce28a85 commit d7561a1
Show file tree
Hide file tree
Showing 10 changed files with 146 additions and 25 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ jobs:

matrix:
os: [ubuntu-latest, macos-latest]
python-version: [3.8, 3.12]
python-version: ["3.10", 3.12]

env:
CRIPT_HOST: https://lb-stage.mycriptapp.org/
Expand Down
105 changes: 105 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
# CRIPT Python SDK Changelog

## Version 2.3.0

**New Features:**

- `cript.API` objects now have a `DataSchema` attribute called `schema`, representing the JSON schema for node validation.
- This includes the ability to enable and disable node validation.
- `cript.API` objects now have `logger` attributes from the Python `logging` module to control logging flows.
- Refactor of Paginator:
- New Paginator objects for accessing data from the CRIPT data bank via search.
- Paginator are now Python iterators. You can use `for node in paginator: ...` directly.
- Paginator now return `cript.Node` objects natively.
- JSON response can be requested from Paginator alternatively. This is helpful for internal work and debugging.
- Additional information is added to the logging message when nodes are validated. For primary nodes, `name` is displayed; for others, the `UUID` is displayed.
- HTTP requests are now optimized, leaving connections open and grouping requests for better performance.
- A native iterator for nodes is now offered. It iterates in depth-first order over all child nodes of the root node. Cycles are automatically broken, and every node is visited exactly once.
- Materials with no identifier issue a warning to users.
- Debugging messages show full API requests and responses for debugging.
- Automated UUID caching for nodes can now be explicitly circumvented when using `cript.load_nodes_from_json`. Mostly useful for development.

**Known Issues and Bugs:**

- Saving projects is not supported. Temporarily, you can use `get_expanded_json` to store a JSON representation of projects, which can be uploaded into CRIPT at a later time.
- BigSMILES search patterns are not supported.
- Searching for more than 1000 pages (10000 entries) is not supported.
- Permission settings in CRIPT do not influence the behavior of the SDK objects.
- Tests that require valid tokens (like saving or searching) are not included in CI/CD tests.

**Bugfixes:**

- `cript.load_nodes_from_json` can now load JSON files that store different nodes in lists or dictionaries.
- Not all nodes were correctly validated at all times, especially if instantiated from JSON. All nodes are automatically validated now.
- The documentation has been updated to remove certain mistakes.
- Users can have only one Python object with the same UUID to avoid mis-updates. This did not work in all cases, but it works in all cases now.

**Breaking Changes:**

- `cript.API()` objects no longer have functions related to JSON schema validation. Please use the new `DataSchema` class instead. The `DataSchema` class can be accessed via the `schema` property of the API class.
- Indirect logging control via the API is defunct. Please use the direct access to the `logger` attribute of API classes to control logging output.
- The SDK used to use `identifier` dictionaries for material identifiers. This is updated to use individual attributes of the material node. This is consistent with the JSON schema and front-end but is a breaking change to older SDK versions and the original CRIPT publication.
- Projects were checked to ensure the presence of material and computation in Experiments. These errors were converted into warnings.

### Health Report

```shell
=============================================================================================== test session starts ===============================================================================================
platform linux -- Python 3.11.2, pytest-7.4.3
plugins: cov-4.1.0
collected 124 items

tests/test_node_util.py ........... [ 8%]
tests/api/test_api.py ..... [ 12%]
tests/api/test_db_schema.py ..... [ 16%]
tests/api/test_search.py .....F [ 21%]
tests/nodes/test_utils.py .. [ 23%]
tests/nodes/primary_nodes/test_collection.py .....F [ 28%]
tests/nodes/primary_nodes/test_computation.py .....F [ 33%]
tests/nodes/primary_nodes/test_computational_process.py ....F [ 37%]
tests/nodes/primary_nodes/test_data.py ....F [ 41%]
tests/nodes/primary_nodes/test_experiment.py ....F [ 45%]
tests/nodes/primary_nodes/test_inventory.py ..F [ 47%]
tests/nodes/primary_nodes/test_material.py ...F [ 50%]
tests/nodes/primary_nodes/test_process.py .....F [ 55%]
tests/nodes/primary_nodes/test_project.py ...F [ 58%]
tests/nodes/primary_nodes/test_reference.py ......F [ 64%]
tests/nodes/subobjects/test_algorithm.py ..F [ 66%]
tests/nodes/subobjects/test_citation.py ..F [ 69%]
tests/nodes/subobjects/test_computational_forcefield.py ..F [ 71%]
tests/nodes/subobjects/test_condition.py ..F [ 74%]
tests/nodes/subobjects/test_equipment.py ..F [ 76%]
tests/nodes/subobjects/test_ingredient.py ..F [ 79%]
tests/nodes/subobjects/test_parameter.py ..F [ 81%]
tests/nodes/subobjects/test_property.py ..F [ 83%]
tests/nodes/subobjects/test_quantity.py ..F [ 86%]
tests/nodes/subobjects/test_software.py ...F [ 89%]
tests/nodes/subobjects/test_software_configuration.py ..F [ 91%]
tests/nodes/supporting_nodes/test_file.py ..s....F [ 98%]
tests/nodes/supporting_nodes/test_user.py .. [100%]
============================================================================================= short test summary info =============================================================================================
FAILED tests/api/test_search.py::test_api_search_bigsmiles - cript.nodes.exceptions.CRIPTJsonDeserializationError: JSON deserialization failed for node type Material with JSON str: Material
FAILED tests/nodes/primary_nodes/test_collection.py::test_integration_collection - AttributeError: 'list' object has no attribute 'starts with'
FAILED tests/nodes/primary_nodes/test_computation.py::test_integration_computation - AttributeError: 'list' object has no attribute 'starts with'
FAILED tests/nodes/primary_nodes/test_computational_process.py::test_integration_computational_process - AttributeError: 'list' object has no attribute 'starts with'
FAILED tests/nodes/primary_nodes/test_data.py::test_integration_data - AttributeError: 'list' object has no attribute 'starts with'
FAILED tests/nodes/primary_nodes/test_experiment.py::test_integration_experiment - AttributeError: 'list' object has no attribute 'starts with'
FAILED tests/nodes/primary_nodes/test_inventory.py::test_integration_inventory - AttributeError: 'list' object has no attribute 'starts with'
FAILED tests/nodes/primary_nodes/test_material.py::test_integration_material - AttributeError: 'list' object has no attribute 'starts with'
FAILED tests/nodes/primary_nodes/test_process.py::test_integration_complex_process - AttributeError: 'list' object has no attribute 'starts with'
FAILED tests/nodes/primary_nodes/test_project.py::test_integration_project - AttributeError: 'list' object has no attribute 'starts with'
FAILED tests/nodes/primary_nodes/test_reference.py::test_integration_reference - IndexError: list index out of range
FAILED tests/nodes/subobjects/test_algorithm.py::test_integration_algorithm - AttributeError: 'list' object has no attribute 'starts with'
FAILED tests/nodes/subobjects/test_citation.py::test_integration_citation - IndexError: list index out of range
FAILED tests/nodes/subobjects/test_computational_forcefield.py::test_integration_computational_forcefield - AttributeError: 'NoneType' object has no attribute 'description'
FAILED tests/nodes/subobjects/test_condition.py::test_integration_process_condition - AttributeError: 'list' object has no attribute 'starts with'
FAILED tests/nodes/subobjects/test_equipment.py::test_integration_equipment - AttributeError: 'list' object has no attribute 'starts with'
FAILED tests/nodes/subobjects/test_ingredient.py::test_integration_ingredient - AttributeError: 'list' object has no attribute 'starts with'
FAILED tests/nodes/subobjects/test_parameter.py::test_integration_parameter - AttributeError: 'list' object has no attribute 'starts with'
FAILED tests/nodes/subobjects/test_property.py::test_integration_material_property - IndexError: list index out of range
FAILED tests/nodes/subobjects/test_quantity.py::test_integration_quantity - AttributeError: 'list' object has no attribute 'starts with'
FAILED tests/nodes/subobjects/test_software.py::test_integration_software - AttributeError: 'list' object has no attribute 'starts with'
FAILED tests/nodes/subobjects/test_software_configuration.py::test_integration_software_configuration - AttributeError: 'list' object has no attribute 'starts with'
FAILED tests/nodes/supporting_nodes/test_file.py::test_integration_file - AttributeError: 'list' object has no attribute 'starts with'
======================================================================== 23 failed, 100 passed, 1 skipped, 1 warning in 905.51s (0:15:05) =========================================================================
```
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
[![License](./CRIPT_full_logo_colored_transparent.png)](https://github.com/C-Accel-CRIPT/Python-SDK/blob/develop/LICENSE.md)

[![License](https://img.shields.io/github/license/C-Accel-CRIPT/cript?style=flat-square)](https://github.com/C-Accel-CRIPT/Python-SDK/blob/develop/LICENSE.md)
[![Python](https://img.shields.io/badge/Language-Python%203.8+-blue?style=flat-square&logo=python)](https://www.python.org/)
[![Python](https://img.shields.io/badge/Language-Python%203.10+-blue?style=flat-square&logo=python)](https://www.python.org/)
[![Code style is black](https://img.shields.io/badge/Code%20Style-black-000000.svg?style=flat-square&logo=python)](https://github.com/psf/black)
[![Link to CRIPT website](https://img.shields.io/badge/platform-criptapp.org-blueviolet?style=flat-square)](https://criptapp.org/)
[![Using Pytest](https://img.shields.io/badge/Dependencies-pytest-green?style=flat-square&logo=Pytest)](https://docs.pytest.org/en/7.2.x/)
Expand Down Expand Up @@ -36,7 +36,7 @@ The CRIPT Python SDK allows programmatic access to the [CRIPT platform](https://

## Installation

CRIPT Python SDK requires Python 3.8+
CRIPT Python SDK requires Python 3.10+

The latest released of CRIPT Python SDK is available on [Python Package Index (PyPI)](https://pypi.org/project/cript/)

Expand Down
6 changes: 3 additions & 3 deletions setup.cfg
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[metadata]
name = cript
version = 2.2.0
version = 2.3.0
description = CRIPT Python SDK
long_description = file: README.md
long_description_content_type = text/markdown
Expand All @@ -14,13 +14,13 @@ classifiers =
Topic :: Scientific/Engineering
Programming Language :: Python :: 3
Programming Language :: Python :: 3 :: Only
Programming Language :: Python :: 3.8
Programming Language :: Python :: 3.10

[options]
package_dir =
=src
packages = find:
python_requires = >=3.8
python_requires = >=3.10
include_package_data = True
install_requires =
requests==2.31.0
Expand Down
18 changes: 12 additions & 6 deletions tests/fixtures/primary_nodes.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,15 @@ def simple_project_node(simple_collection_node) -> cript.Project:
def complex_project_dict(complex_collection_node, simple_material_node, complex_user_node) -> dict:
project_dict = {"node": ["Project"]}
project_dict["locked"] = True
project_dict["model_version"] = "1.0.0"

# project_dict["model_version"] = "1.0.0"
# project_dict["updated_by"] = json.loads(copy.deepcopy(complex_user_node).get_expanded_json())
# project_dict["created_by"] = json.loads(complex_user_node.get_expanded_json())

project_dict["model_version"] = "1.0.1"
# project_dict["updated_by"] = json.loads(copy.deepcopy(complex_user_node).get_expanded_json())
# project_dict["created_by"] = json.loads(complex_user_node.get_expanded_json())

project_dict["public"] = True
project_dict["name"] = "my project name"
project_dict["notes"] = "my project notes"
Expand Down Expand Up @@ -60,7 +66,7 @@ def fixed_cyclic_project_node() -> cript.Project:
project_json_string += '"created_at": "2024-03-12 15:58:12.486673",\n'
project_json_string += '"updated_at": "2024-03-12 15:58:12.486681",\n'
project_json_string += '"email": "[email protected]",\n'
project_json_string += '"model_version": "1.0.0",\n'
project_json_string += '"model_version": "1.0.1",\n'
project_json_string += '"orcid": "0000-0002-0000-0000",\n'
project_json_string += '"picture": "/my/picture/path",\n'
project_json_string += '"username": "testuser"\n'
Expand All @@ -72,13 +78,13 @@ def fixed_cyclic_project_node() -> cript.Project:
project_json_string += '"created_at": "2024-03-12 15:58:12.486673",\n'
project_json_string += '"updated_at": "2024-03-12 15:58:12.486681",\n'
project_json_string += '"email": "[email protected]",\n'
project_json_string += '"model_version": "1.0.0",\n'
project_json_string += '"model_version": "1.0.1",\n'
project_json_string += '"orcid": "0000-0002-0000-0000",\n'
project_json_string += '"picture": "/my/picture/path",\n'
project_json_string += '"username": "testuser"\n'
project_json_string += "},\n"
project_json_string += '"locked": true,\n'
project_json_string += '"model_version": "1.0.0",\n'
project_json_string += '"model_version": "1.0.1",\n'
project_json_string += '"public": true,\n'
project_json_string += '"name": "my project name",\n'
project_json_string += '"notes": "my project notes",\n'
Expand Down Expand Up @@ -126,7 +132,7 @@ def fixed_cyclic_project_node() -> cript.Project:
project_json_string += '"node": ["Property"],\n'
project_json_string += '"uid": "_:fc504202-6fdd-43c7-830d-40c7d3f0cb8c",\n'
project_json_string += '"uuid": "fc504202-6fdd-43c7-830d-40c7d3f0cb8c",\n'
project_json_string += '"key": "modulus_shear",\n'
project_json_string += '"key": "enthalpy",\n'
project_json_string += '"type": "value",\n'
project_json_string += '"value": 5.0,\n'
project_json_string += '"unit": "GPa",\n'
Expand Down Expand Up @@ -213,7 +219,7 @@ def fixed_cyclic_project_node() -> cript.Project:
project_json_string += '"node": ["Property"],\n'
project_json_string += '"uid": "_:fde629f5-8d3a-4546-8cd3-9de63b990187",\n'
project_json_string += '"uuid": "fde629f5-8d3a-4546-8cd3-9de63b990187",\n'
project_json_string += '"key": "modulus_shear",\n'
project_json_string += '"key": "enthalpy",\n'
project_json_string += '"type": "value",\n'
project_json_string += '"value": 5.0,\n'
project_json_string += '"unit": "GPa",\n'
Expand Down
8 changes: 4 additions & 4 deletions tests/fixtures/subobjects.py
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ def complex_property_node(complex_material_node, complex_condition_node, complex
a maximal property sub-object with all possible fields filled
"""
my_complex_property = cript.Property(
key="modulus_shear",
key="enthalpy",
type="value",
value=5.0,
unit="GPa",
Expand All @@ -144,7 +144,7 @@ def complex_property_node(complex_material_node, complex_condition_node, complex
def complex_property_dict(complex_material_node, complex_condition_dict, complex_citation_dict, complex_data_node, simple_process_node, simple_computation_node) -> dict:
ret_dict = {
"node": ["Property"],
"key": "modulus_shear",
"key": "enthalpy",
"type": "value",
"value": 5.0,
"unit": "GPa",
Expand All @@ -165,7 +165,7 @@ def complex_property_dict(complex_material_node, complex_condition_dict, complex
@pytest.fixture(scope="function")
def simple_property_node() -> cript.Property:
my_property = cript.Property(
key="modulus_shear",
key="enthalpy",
type="value",
value=5.0,
unit="GPa",
Expand All @@ -177,7 +177,7 @@ def simple_property_node() -> cript.Property:
def simple_property_dict() -> dict:
ret_dict = {
"node": ["Property"],
"key": "modulus_shear",
"key": "enthalpy",
"type": "value",
"value": 5.0,
"unit": "GPa",
Expand Down
10 changes: 10 additions & 0 deletions tests/fixtures/supporting_nodes.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,16 @@ def complex_user_dict(cript_api) -> dict:
user_dict = json.loads(user_node.get_json().json)
print("8888888--------")
print(user_dict)

# def complex_user_dict() -> dict: #old code
# user_dict = {"node": ["User"]}
# user_dict["created_at"] = str(datetime.datetime.now())
# user_dict["model_version"] = "1.0.1"
# user_dict["picture"] = "/my/picture/path"
# user_dict["updated_at"] = str(datetime.datetime.now())
# user_dict["username"] = "testuser"
# user_dict["email"] = "[email protected]"
# user_dict["orcid"] = "0000-0002-0000-0000"
return user_dict


Expand Down
2 changes: 1 addition & 1 deletion tests/nodes/primary_nodes/test_material.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ def test_create_complex_material(cript_api, simple_material_node, simple_computa
component = [simple_material_node]
forcefield = simple_computational_forcefield_node

my_property = [cript.Property(key="modulus_shear", type="min", value=1.23, unit="gram")]
my_property = [cript.Property(key="rho_z", type="min", value=1.23, unit="gram")]

my_material = cript.Material(
name=material_name,
Expand Down
4 changes: 2 additions & 2 deletions tests/nodes/subobjects/test_property.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ def test_json(complex_property_node, complex_property_dict):


def test_setter_getter(complex_property_node, simple_material_node, simple_process_node, complex_condition_node, simple_data_node, simple_computation_node, complex_citation_node):
complex_property_node.key = "modulus_loss"
assert complex_property_node.key == "modulus_loss"
complex_property_node.key = "rho_z"
assert complex_property_node.key == "rho_z"

complex_property_node.type = "min"
assert complex_property_node.type == "min"
Expand Down
12 changes: 6 additions & 6 deletions tests/test_node_util.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,8 @@ def test_uid_deserialization(simple_algorithm_node, complex_parameter_node, simp
material = cript.Material(name="my material", bigsmiles="{[][$]CC[$][]}")

computation = cript.Computation(name="my computation name", type="analysis")
property1 = cript.Property("modulus_shear", "value", 5.0, "GPa", computation=[computation])
property2 = cript.Property("modulus_loss", "value", 5.0, "GPa", computation=[computation])
property1 = cript.Property("enthalpy", "value", 5.0, "GPa", computation=[computation])
property2 = cript.Property("rho_z", "value", 5.0, "GPa", computation=[computation])
material.property = [property1, property2]

material2 = cript.load_nodes_from_json(material.json)
Expand All @@ -50,7 +50,7 @@ def test_uid_deserialization(simple_algorithm_node, complex_parameter_node, simp
"node": ["Property"],
"uid": "_:82e7270e-9f35-4b35-80a2-faa6e7f670be",
"uuid": "82e7270e-9f35-4b35-80a2-faa6e7f670be",
"key": "modulus_shear",
"key": "enthalpy",
"type": "value",
"value": 5.0,
"unit": "GPa",
Expand All @@ -60,7 +60,7 @@ def test_uid_deserialization(simple_algorithm_node, complex_parameter_node, simp
"node": ["Property"],
"uid": "_:fc4dfa5e-742c-4d0b-bb66-2185461f4582",
"uuid": "fc4dfa5e-742c-4d0b-bb66-2185461f4582",
"key": "modulus_loss",
"key": "rho_z",
"type": "value",
"value": 5.0,
"unit": "GPa",
Expand Down Expand Up @@ -92,7 +92,7 @@ def test_uid_deserialization(simple_algorithm_node, complex_parameter_node, simp
# ],
# "uid": "_:82e7270e-9f35-4b35-80a2-faa6e7f670be",
# "uuid": "82e7270e-9f35-4b35-80a2-faa6e7f670be",
# "key": "modulus_shear",
# "key": "enthalpy",
# "type": "value",
# "value": 5.0,
# "unit": "GPa",
Expand All @@ -111,7 +111,7 @@ def test_uid_deserialization(simple_algorithm_node, complex_parameter_node, simp
# ],
# "uid": "_:fc4dfa5e-742c-4d0b-bb66-2185461f4582",
# "uuid": "fc4dfa5e-742c-4d0b-bb66-2185461f4582",
# "key": "modulus_loss",
# "key": "rho_z",
# "type": "value",
# "value": 5.0,
# "unit": "GPa",
Expand Down

0 comments on commit d7561a1

Please sign in to comment.