Skip to content

Commit

Permalink
add missing methods for Template, Layout, Generator (#200)
Browse files Browse the repository at this point in the history
  • Loading branch information
viseshrp authored Dec 11, 2024
1 parent 07c1485 commit 23bdd12
Show file tree
Hide file tree
Showing 3 changed files with 169 additions and 21 deletions.
22 changes: 19 additions & 3 deletions src/ansys/dynamicreporting/core/serverless/adr.py
Original file line number Diff line number Diff line change
Expand Up @@ -361,6 +361,8 @@ def session_guid(self) -> uuid.UUID:
def create_item(self, item_type: Type[Item], **kwargs: Any) -> Item:
if not issubclass(item_type, Item):
raise TypeError(f"{item_type} is not valid")
if not kwargs:
raise ADRException("At least one keyword argument must be provided to create the item.")
return item_type.create(
session=kwargs.pop("session", self._session),
dataset=kwargs.pop("dataset", self._dataset),
Expand All @@ -370,6 +372,10 @@ def create_item(self, item_type: Type[Item], **kwargs: Any) -> Item:
def create_template(self, template_type: Type[Template], **kwargs: Any) -> Template:
if not issubclass(template_type, Template):
raise TypeError(f"{template_type} is not valid")
if not kwargs:
raise ADRException(
"At least one keyword argument must be provided to create the template."
)
template = template_type.create(**kwargs)
parent = kwargs.get("parent")
if parent is not None:
Expand All @@ -378,13 +384,17 @@ def create_template(self, template_type: Type[Template], **kwargs: Any) -> Templ
return template

def get_report(self, **kwargs) -> Template:
if not kwargs:
raise ADRException(
"At least one keyword argument must be provided to fetch the report."
)
try:
return Template.get(parent=None, **kwargs)
except Exception as e:
raise e

def get_reports(
self, fields: Optional[list] = None, flat: bool = False
self, *, fields: Optional[list] = None, flat: bool = False
) -> Union[ObjectSet, list]:
# return list of reports by default.
# if fields are mentioned, return value list
Expand All @@ -397,7 +407,7 @@ def get_reports(

return out

def get_list_reports(self, r_type: str = "name") -> Union[ObjectSet, list]:
def get_list_reports(self, *, r_type: str = "name") -> Union[ObjectSet, list]:
supported_types = ("name", "report")
if r_type not in supported_types:
raise ADRException(f"r_type must be one of {supported_types}")
Expand All @@ -412,8 +422,12 @@ def get_list_reports(self, r_type: str = "name") -> Union[ObjectSet, list]:
return self.get_reports()

def render_report(
self, context: Optional[dict] = None, item_filter: str = "", **kwargs: Any
self, *, context: Optional[dict] = None, item_filter: str = "", **kwargs: Any
) -> str:
if not kwargs:
raise ADRException(
"At least one keyword argument must be provided to fetch the report."
)
try:
return Template.get(**kwargs).render(
request=self._request, context=context, item_filter=item_filter
Expand All @@ -424,6 +438,7 @@ def render_report(
def query(
self,
query_type: Union[Session, Dataset, Type[Item], Type[Template]],
*,
query: str = "",
**kwargs: Any,
) -> ObjectSet:
Expand Down Expand Up @@ -482,6 +497,7 @@ def copy_objects(
self,
object_type: Union[Session, Dataset, Type[Item], Type[Template]],
target_database: str,
*,
query: str = "",
target_media_dir: str = "",
test: bool = False,
Expand Down
5 changes: 3 additions & 2 deletions src/ansys/dynamicreporting/core/serverless/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -145,10 +145,10 @@ class BaseModel(metaclass=BaseMeta):
) # tracks the corresponding ORM instance

def __repr__(self) -> str:
return f"<{self.__class__.__name__}: {self}>"
return f"<{self.__class__.__name__}: {self.guid}>"

def __str__(self) -> str:
return f"{self.__class__.__name__} object {self.guid}"
return f"<{self.__class__.__name__}: {self.guid}>"

def __post_init__(self):
self._validate_field_types()
Expand Down Expand Up @@ -358,6 +358,7 @@ def from_db(cls, orm_instance, parent=None):
elif isinstance(value, Manager):
type_ = get_origin(field_type)
args = get_args(field_type)
# todo: move this check to the metaclass
if type_ is None or not issubclass(type_, Iterable) or len(args) != 1:
raise TypeError(
f"The field '{attr}' in the dataclass must be a generic iterable"
Expand Down
163 changes: 147 additions & 16 deletions src/ansys/dynamicreporting/core/serverless/template.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@ def __post_init__(self):
raise TypeError("Cannot instantiate Template directly. Use Template.create()")
super().__post_init__()

def __str__(self) -> str:
return f"<{self.__class__.__name__}: {self.name}>"

@property
def type(self):
return self.report_type
Expand All @@ -61,6 +64,10 @@ def save(self, **kwargs):
)
children_order = []
for child in self.children:
if not isinstance(child, Template):
raise TypeError(
f"Failed to save template because child '{child}' is not a Template object"
)
if not child._saved:
raise Template.NotSaved(
extra_detail="Failed to save template because its children are not saved"
Expand Down Expand Up @@ -155,12 +162,12 @@ def get_filter(self):

def set_filter(self, filter_str):
if not isinstance(filter_str, str):
raise TypeError("Error: filter value should be a string")
raise TypeError("filter value should be a string")
self.item_filter = filter_str

def add_filter(self, filter_str=""):
if not isinstance(filter_str, str):
raise TypeError("Error: filter value should be a string")
raise TypeError("filter value should be a string")
self.item_filter += filter_str

def get_params(self) -> dict:
Expand All @@ -170,39 +177,79 @@ def set_params(self, new_params: dict) -> None:
if new_params is None:
new_params = {}
if not isinstance(new_params, dict):
raise TypeError("Error: input must be a dictionary")
raise TypeError("input must be a dictionary")
self.params = json.dumps(new_params)

def add_params(self, new_params: dict):
if new_params is None:
new_params = {}
if not isinstance(new_params, dict):
raise TypeError("Error: input must be a dictionary")
curr_params = json.loads(self.params)
self.params = json.dumps(curr_params | new_params)
raise TypeError("input must be a dictionary")
curr_params = self.get_params()
self.set_params(curr_params | new_params)

def get_property(self):
params = json.loads(self.params)
return params.get("properties", {})
return self.get_params().get("properties", {})

def set_property(self, new_props: dict):
if new_props is None:
new_props = {}
if not isinstance(new_props, dict):
raise TypeError("Error: input must be a dictionary")
params = json.loads(self.params)
raise TypeError("input must be a dictionary")
params = self.get_params()
params["properties"] = new_props
self.params = json.dumps(params)
self.set_params(params)

def add_property(self, new_props: dict):
if new_props is None:
new_props = {}
if not isinstance(new_props, dict):
raise TypeError("Error: input must be a dictionary")
params = json.loads(self.params)
raise TypeError("input must be a dictionary")
params = self.get_params()
curr_props = params.get("properties", {})
params["properties"] = curr_props | new_props
self.params = json.dumps(params)
self.set_params(params)

def get_sort_fields(self):
return self.get_params().get("sort_fields", [])

def set_sort_fields(self, sort_field):
if not isinstance(sort_field, list):
raise ValueError("sorting filter is not a list")
params = self.get_params()
params["sort_fields"] = sort_field
self.set_params(params)

def add_sort_fields(self, sort_field):
if not isinstance(sort_field, list):
raise ValueError("sorting filter is not a list")
params = self.get_params()
params["sort_fields"].extend(sort_field)
self.set_params(params)

def get_sort_selection(self):
return self.get_params().get("sort_selection", "")

def set_sort_selection(self, value="all"):
if not isinstance(value, str):
raise ValueError("sort selection input should be a string")
if value not in ("all", "first", "last"):
raise ValueError("sort selection not among the acceptable inputs")
params = self.get_params()
params["sort_selection"] = value
self.set_params(params)

def get_filter_mode(self):
return self.get_params().get("filter_type", "items")

def set_filter_mode(self, value="items"):
if not isinstance(value, str):
raise ValueError("filter mode input should be a string")
if value not in ("items", "root_replace", "root_append"):
raise ValueError("filter mode not among the acceptable inputs")
params = self.get_params()
params["filter_type"] = value
self.set_params(params)

def render(self, context=None, request=None, item_filter="") -> str:
if context is None:
Expand Down Expand Up @@ -231,7 +278,71 @@ def render(self, context=None, request=None, item_filter="") -> str:


class Layout(Template):
pass
def get_column_count(self):
return self.get_params().get("column_count", 1)

def set_column_count(self, value):
if not isinstance(value, int):
raise ValueError("column count input should be an integer")
if value <= 0:
raise ValueError("column count input should be larger than 0")
params = self.get_params()
params["column_count"] = value
self.set_params(params)

def get_column_widths(self):
return self.get_params().get("column_widths", [1.0])

def set_column_widths(self, value):
if not isinstance(value, list):
raise ValueError("column widths input should be a list")
if not all(isinstance(x, (int, float)) for x in value):
raise ValueError("column widths input should be a list of integers or floats")
if not all(x > 0 for x in value):
raise ValueError("column widths input should be larger than 0")
params = self.get_params()
params["column_widths"] = value
self.set_params(params)

def get_html(self):
return self.get_params().get("HTML", "")

def set_html(self, value=""):
if not isinstance(value, str):
raise ValueError("input needs to be a string")
params = self.get_params()
params["HTML"] = value
self.set_params(params)

def get_comments(self):
return self.get_params().get("comments", "")

def set_comments(self, value=""):
if not isinstance(value, str):
raise ValueError("input needs to be a string")
params = self.get_params()
params["comments"] = value
self.set_params(params)

def get_transpose(self):
return self.get_params().get("transpose", 0)

def set_transpose(self, value=0):
if not isinstance(value, int):
raise ValueError("input needs to be an integer")
params = self.get_params()
params["transpose"] = value
self.set_params(params)

def get_skip(self):
return self.get_params().get("skip_empty", 0)

def set_skip(self, value=0):
if not isinstance(value, int) or value not in (0, 1):
raise ValueError("input needs to be an integer (0 or 1)")
params = self.get_params()
params["skip_empty"] = value
self.set_params(params)


class BasicLayout(Layout):
Expand Down Expand Up @@ -299,7 +410,27 @@ class UserDefinedLayout(Layout):


class Generator(Template):
pass
def get_generated_items(self):
return self.get_params().get("generate_merge", "add")

def set_generated_items(self, value):
if not isinstance(value, str):
raise ValueError("generated items should be a string")
if value not in ("add", "replace"):
raise ValueError("input should be add or replace")
params = self.get_params()
params["generate_merge"] = value
self.set_params(params)

def get_append_tags(self):
return self.get_params().get("generate_appendtags", True)

def set_append_tags(self, value=True):
if not isinstance(value, bool):
raise ValueError("value should be True / False")
params = self.get_params()
params["generate_appendtags"] = value
self.set_params(params)


class TableMergeGenerator(Generator):
Expand Down

0 comments on commit 23bdd12

Please sign in to comment.