Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
74 commits
Select commit Hold shift + click to select a range
d665902
disable ci
viseshrp Feb 26, 2025
b5f9ba3
guids are always str
viseshrp Feb 26, 2025
896e784
update tests
viseshrp Feb 26, 2025
a158456
Revert "disable ci"
viseshrp Feb 26, 2025
eb2515b
Reapply "disable ci"
viseshrp Apr 3, 2025
613676d
Merge branch 'main' into vr/slst
viseshrp Apr 3, 2025
5d7d687
fix population of dynamic props
viseshrp Apr 3, 2025
aa96b52
add InvalidFieldError
viseshrp Apr 3, 2025
89e8ad6
update tests
viseshrp Apr 3, 2025
9212978
Update test_item.py
viseshrp Apr 3, 2025
2ff331d
add recursive option for as_dict
viseshrp Apr 4, 2025
85c3731
update tests for tags
viseshrp Apr 4, 2025
42e65bd
test for as_dict
viseshrp Apr 4, 2025
e4f7a6e
Update test_template.py
viseshrp Apr 4, 2025
9143744
Update test_item.py
viseshrp Apr 4, 2025
f5acd02
Update conftest.py
viseshrp Apr 4, 2025
bfa6b1a
Update conftest.py
viseshrp Apr 4, 2025
85f4feb
Update conftest.py
viseshrp Apr 4, 2025
cf9e689
Revert "Update conftest.py"
viseshrp Apr 4, 2025
0b749fe
test for children temps
viseshrp Apr 4, 2025
1566ca0
Update test_template.py
viseshrp Apr 7, 2025
7143bdf
Update test_template.py
viseshrp Apr 7, 2025
021e419
Update template.py
viseshrp Apr 7, 2025
cf8a7ee
more error handling for base save method
viseshrp Apr 7, 2025
d17df43
right exception types for template save
viseshrp Apr 7, 2025
d568c06
Update test_template.py
viseshrp Apr 7, 2025
4ddef26
Update test_template.py
viseshrp Apr 7, 2025
af6f95e
Update test_template.py
viseshrp Apr 7, 2025
19b6f22
Update base.py
viseshrp Apr 7, 2025
2167ce2
Update test_item.py
viseshrp Apr 7, 2025
6c7a3a8
fix get_or_create
viseshrp Apr 7, 2025
8fcfbe1
Update test_item.py
viseshrp Apr 7, 2025
3456a5b
Update test_item.py
viseshrp Apr 8, 2025
3c9cee9
Update test_item.py
viseshrp Apr 8, 2025
b3c2964
handle basemodel instances in get
viseshrp Apr 8, 2025
2c54707
dont allow content kwarg in some
viseshrp Apr 8, 2025
fa8a2f2
dont allow children kwarg in some
viseshrp Apr 8, 2025
f3c4b32
update tests
viseshrp Apr 8, 2025
423a13e
Update test_template.py
viseshrp Apr 8, 2025
6e12c1e
update tests
viseshrp Apr 8, 2025
46293ee
change ObjectSet.values_list
viseshrp Apr 8, 2025
7ee47b2
add tests for ObjectSet
viseshrp Apr 8, 2025
759b641
Update test_item.py
viseshrp Apr 8, 2025
d154f1e
Revert "Reapply "disable ci""
viseshrp Apr 8, 2025
d91f157
Reapply disable ci
viseshrp Apr 8, 2025
419ed5a
tests for tables
viseshrp Apr 9, 2025
2a837ff
tests for trees
viseshrp Apr 9, 2025
6d228d3
Update test_item.py
viseshrp Apr 9, 2025
c3b9b4a
Update test_item.py
viseshrp Apr 9, 2025
0840575
fix None check in Validator
viseshrp Apr 9, 2025
c899b74
Update item.py
viseshrp Apr 9, 2025
049c7cd
Bypass __init__ to skip validation
viseshrp Apr 9, 2025
0547f02
Update test_item.py
viseshrp Apr 9, 2025
3d4de9b
remove get_or_create
viseshrp Apr 9, 2025
f933dc7
more tree tests
viseshrp Apr 9, 2025
e8087fd
fix Item instantiation error
viseshrp Apr 9, 2025
d911f43
fix super class checks
viseshrp Apr 10, 2025
814784e
tests for item class methods
viseshrp Apr 10, 2025
4701ab3
Update test_item.py
viseshrp Apr 10, 2025
97a322c
Update test_item.py
viseshrp Apr 10, 2025
2f4f72c
raise during png conversion
viseshrp Apr 10, 2025
bd8d8f6
Update test_item.py
viseshrp Apr 10, 2025
a9e6ec4
Update test_item.py
viseshrp Apr 10, 2025
3060e74
Update test_item.py
viseshrp Apr 10, 2025
6d4cec0
Update test_item.py
viseshrp Apr 10, 2025
f8aeb9c
fix File and Image handling
viseshrp Apr 10, 2025
042bc65
Update test_item.py
viseshrp Apr 10, 2025
d1a2eed
update image conv error
viseshrp Apr 10, 2025
7043d18
Update test_item.py
viseshrp Apr 10, 2025
0800ca0
Update test_item.py
viseshrp Apr 10, 2025
ed06240
Update test_item.py
viseshrp Apr 10, 2025
ed5307c
Revert "Reapply disable ci"
viseshrp Apr 10, 2025
fe4a04a
Merge branch 'main' into vr/slst
viseshrp Apr 10, 2025
91999e7
Update ci_cd.yml
viseshrp Apr 10, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 9 additions & 10 deletions .github/workflows/ci_cd.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: PyAnsys code style checks
uses: ansys/actions/code-style@v8
uses: ansys/actions/code-style@v9.0
with:
python-version: ${{ env.MAIN_PYTHON_VERSION }}
show-diff-on-failure: false
Expand All @@ -55,7 +55,7 @@ jobs:
python-version: [ '3.10', '3.11', '3.12', '3.13' ]
steps:
- name: Build wheelhouse
uses: ansys/actions/build-wheelhouse@v8
uses: ansys/actions/build-wheelhouse@v9.0
with:
library-name: ${{ env.PACKAGE_NAME }}
operating-system: ${{ matrix.os }}
Expand All @@ -75,7 +75,6 @@ jobs:
matrix:
os: [ ubuntu-latest ]
python-version: [ '3.10', '3.11', '3.12', '3.13' ]

steps:
- uses: actions/checkout@v4

Expand Down Expand Up @@ -118,7 +117,7 @@ jobs:
# needs: [docs-style]
steps:
- name: Run Ansys documentation building action
uses: ansys/actions/doc-build@v8
uses: ansys/actions/doc-build@v9.0
with:
python-version: ${{ env.MAIN_PYTHON_VERSION }}
check-links: false
Expand All @@ -130,7 +129,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Build library source and wheel artifacts
uses: ansys/actions/build-library@v8
uses: ansys/actions/build-library@v9.0
with:
library-name: ${{ env.PACKAGE_NAME }}
python-version: ${{ env.MAIN_PYTHON_VERSION }}
Expand All @@ -142,14 +141,14 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Release to the public PyPI repository
uses: ansys/actions/release-pypi-public@v8
uses: ansys/actions/release-pypi-public@v9.0
with:
library-name: ${{ env.PACKAGE_NAME }}
twine-username: "__token__"
twine-token: ${{ secrets.PYPI_TOKEN }}

- name: Release to GitHub
uses: ansys/actions/release-github@v8
uses: ansys/actions/release-github@v9.0
if: ${{ !env.ACT }}
with:
library-name: ${{ env.PACKAGE_NAME }}
Expand All @@ -161,7 +160,7 @@ jobs:
needs: [ docs, package ]
steps:
- name: Deploy the latest documentation
uses: ansys/actions/doc-deploy-dev@v8
uses: ansys/actions/doc-deploy-dev@v9.0
if: ${{ !env.ACT }}
with:
cname: ${{ env.DOCUMENTATION_CNAME }}
Expand All @@ -176,7 +175,7 @@ jobs:
needs: [ docs, release ]
steps:
- name: Deploy the stable documentation
uses: ansys/actions/doc-deploy-stable@v8
uses: ansys/actions/doc-deploy-stable@v9.0
if: ${{ !env.ACT }}
with:
cname: ${{ env.DOCUMENTATION_CNAME }}
Expand All @@ -194,7 +193,7 @@ jobs:
- name: Microsoft Teams Notification
uses: jdcargile/ms-teams-notification@v1.4
with:
github-token: ${{ github.token }} # this will use the runner's token.
github-token: ${{ github.token }}
ms-teams-webhook-uri: ${{ secrets.MS_TEAMS_WEBHOOK_URI_CI }}
notification-summary: CI build failure
notification-color: dc3545
Expand Down
6 changes: 6 additions & 0 deletions src/ansys/dynamicreporting/core/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -135,3 +135,9 @@ class IntegrityError(ADRException):
"""Exception raised if there is a constraint violation while saving an object in the database."""

detail = "A database integrity check failed."


class InvalidFieldError(ADRException):
"""Exception raised if a field is not valid."""

detail = "Field is invalid."
12 changes: 9 additions & 3 deletions src/ansys/dynamicreporting/core/serverless/adr.py
Original file line number Diff line number Diff line change
Expand Up @@ -818,10 +818,16 @@ def copy_objects(
"'target_media_dir' argument must be specified because one of the objects"
" contains media to copy.'"
)
# save or load sessions, datasets - since it is possible they are shared
# try to load sessions, datasets - since it is possible they are shared
# and were saved already.
session, _ = Session.get_or_create(**item.session.as_dict(), using=target_database)
dataset, _ = Dataset.get_or_create(**item.dataset.as_dict(), using=target_database)
try:
session = Session.get(guid=item.session.guid, using=target_database)
except Session.DoesNotExist:
session = Session.create(**item.session.as_dict(), using=target_database)
try:
dataset = Dataset.get(guid=item.dataset.guid, using=target_database)
except Dataset.DoesNotExist:
dataset = Dataset.create(**item.dataset.as_dict(), using=target_database)
item.session = session
item.dataset = dataset
copy_list.append(item)
Expand Down
82 changes: 41 additions & 41 deletions src/ansys/dynamicreporting/core/serverless/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@
from django.db.utils import IntegrityError as DBIntegrityError

from ..exceptions import (
ADRException,
IntegrityError,
InvalidFieldError,
MultipleObjectsReturnedError,
ObjectDoesNotExistError,
ObjectNotSavedError,
Expand All @@ -44,7 +44,9 @@ def wrapper(*args, **kwargs):
try:
return func(*args, **kwargs)
except (FieldError, FieldDoesNotExist, ValidationError, DataError) as e:
raise ADRException(extra_detail=f"One or more fields set or accessed are invalid: {e}")
raise InvalidFieldError(
extra_detail=f"One or more fields set or accessed are invalid: {e}"
)

return wrapper

Expand Down Expand Up @@ -75,13 +77,11 @@ def __new__(
if parents:
# dynamically make the properties listed into class attrs
if "_properties" in namespace:
dynamic_props_field = namespace["_properties"]
if hasattr(dynamic_props_field, "default"):
props = dynamic_props_field.default
new_namespace = {**namespace}
for prop in props:
new_namespace[prop] = None
new_cls = super_new(mcs, cls_name, bases, new_namespace, **kwargs)
props = namespace["_properties"]
new_namespace = {**namespace}
for prop in props:
new_namespace[prop] = None
new_cls = super_new(mcs, cls_name, bases, new_namespace, **kwargs)
# save every class extending BaseModel
mcs._cls_registry[cls_name] = new_cls
# add exceptions
Expand Down Expand Up @@ -266,7 +266,7 @@ def _orm_db(self) -> str:
def db(self):
return self._orm_db

def as_dict(self):
def as_dict(self, recursive=False) -> dict[str, Any]:
out_dict = {}
# use a combination of vars and fields
cls_fields = set(self._get_field_names() + self._get_var_field_names())
Expand All @@ -276,6 +276,9 @@ def as_dict(self):
value = getattr(self, field_, None)
if value is None: # skip and use defaults
continue
if isinstance(value, list) and recursive:
# convert to guids
value = [obj.guid for obj in value]
out_dict[field_] = value
return out_dict

Expand All @@ -293,7 +296,14 @@ def _prepare_for_save(self, **kwargs):
continue
if isinstance(value, list):
objs = [obj._orm_instance for obj in value]
getattr(self._orm_instance, field_).add(*objs)
try:
getattr(self._orm_instance, field_).add(*objs)
except (ObjectDoesNotExist, ValueError) as e:
if value:
obj_cls = value[0].__class__
raise obj_cls.NotSaved(extra_detail=str(e))
else:
raise ValueError(str(e))
else:
if isinstance(value, BaseModel): # relations
try:
Expand Down Expand Up @@ -340,7 +350,7 @@ def delete(self, **kwargs):
def from_db(cls, orm_instance, parent=None):
cls_fields = dict(cls._get_field_names(with_types=True, include_private=True))
model_fields = cls._get_orm_field_names(orm_instance)
obj = cls()
obj = cls.__new__(cls) # Bypass __init__ to skip validation
for field_ in model_fields:
if field_ in cls_fields:
attr = field_
Expand Down Expand Up @@ -416,6 +426,11 @@ def create(cls, **kwargs):
@classmethod
@handle_field_errors
def get(cls, **kwargs):
"""Get an object from the database using the ORM model."""
# convert basemodel instances to orm instances
for key, value in kwargs.items():
if isinstance(value, BaseModel):
kwargs[key] = value._orm_instance
try:
orm_instance = cls._orm_model_cls.objects.using(kwargs.pop("using", "default")).get(
**kwargs
Expand All @@ -429,39 +444,26 @@ def get(cls, **kwargs):

@classmethod
@handle_field_errors
def get_or_create(cls, **kwargs):
try:
return cls.get(**kwargs), False
except cls.DoesNotExist:
# Try to create an object using passed params.
try:
return cls.create(**kwargs), True
except cls.IntegrityError:
try:
return cls.get(**kwargs), False
except cls.DoesNotExist:
pass
raise

@classmethod
@handle_field_errors
def filter(cls, **kwargs):
def filter(cls, **kwargs) -> "ObjectSet":
for key, value in kwargs.items():
if isinstance(value, BaseModel):
kwargs[key] = value._orm_instance
qs = cls._orm_model_cls.objects.using(kwargs.pop("using", "default")).filter(**kwargs)
return ObjectSet(_model=cls, _orm_model=cls._orm_model_cls, _orm_queryset=qs)

@classmethod
@handle_field_errors
def find(cls, query="", **kwargs):
def find(cls, query="", **kwargs) -> "ObjectSet":
qs = cls._orm_model_cls.find(query=query, **kwargs)
return ObjectSet(_model=cls, _orm_model=cls._orm_model_cls, _orm_queryset=qs)

def get_tags(self):
def get_tags(self) -> str:
return self.tags

def set_tags(self, tag_str):
def set_tags(self, tag_str: str) -> None:
self.tags = tag_str

def add_tag(self, tag, value=None):
def add_tag(self, tag: str, value: str | None = None) -> None:
self.rem_tag(tag)
tags = shlex.split(self.get_tags())
if value:
Expand All @@ -470,14 +472,14 @@ def add_tag(self, tag, value=None):
tags.append(tag)
self._rebuild_tags(tags)

def rem_tag(self, tag):
def rem_tag(self, tag: str) -> None:
tags = shlex.split(self.get_tags())
for t in tags:
if t == tag or t.split("=")[0] == tag:
tags.remove(t)
self._rebuild_tags(tags)

def remove_tag(self, tag):
def remove_tag(self, tag: str) -> None:
self.rem_tag(tag)


Expand Down Expand Up @@ -532,8 +534,8 @@ def delete(self):

def values_list(self, *fields, flat=False):
if flat and len(fields) > 1:
raise TypeError(
"'flat' is not valid when values_list is called with more than one " "field."
raise ValueError(
"'flat' is not valid when values_list is called with more than one field."
)
ret = []
for obj in self._obj_set:
Expand All @@ -555,11 +557,9 @@ def __get__(self, obj, obj_type=None):
return getattr(obj, self._name, self._default)

def __set__(self, obj, value):
cleaned_value = None
if value is not None:
cleaned_value = self.process(value, obj)
cleaned_value = self.process(value, obj)
setattr(obj, self._name, cleaned_value)

@abstractmethod
def process(self, value, obj):
pass
pass # pragma: no cover
Loading