-
-
+
+
+
+
+
-
-
-
-
-
-
diff --git a/utilities/misc.py b/utilities/misc.py
index fddf61dd..6aa3098c 100644
--- a/utilities/misc.py
+++ b/utilities/misc.py
@@ -1,20 +1,15 @@
import base64
import hashlib
import hmac
-import html
import json
import logging
import uuid
from collections import defaultdict
from datetime import datetime
-from enum import Enum
-from types import NoneType
from typing import Any, Dict, List, TYPE_CHECKING
from django.conf import settings as s
from django.db import transaction
-from envipy_additional_information import NAME_MAPPING, EnviPyModel, Interval
-from pydantic import BaseModel, HttpUrl
from epdb.models import (
Compound,
@@ -49,183 +44,6 @@ if TYPE_CHECKING:
from epdb.logic import SPathway
-class HTMLGenerator:
- registry = {x.__name__: x for x in NAME_MAPPING.values()}
-
- @staticmethod
- def generate_html(additional_information: "EnviPyModel", prefix="") -> str:
- from typing import Union, get_args, get_origin
-
- if isinstance(additional_information, type):
- clz_name = additional_information.__name__
- else:
- clz_name = additional_information.__class__.__name__
-
- widget = f'
{clz_name}
'
-
- if hasattr(additional_information, "uuid"):
- uuid = additional_information.uuid
- widget += f'
'
-
- for name, field in additional_information.model_fields.items():
- value = getattr(additional_information, name, None)
- full_name = f"{clz_name}__{prefix}__{name}"
- annotation = field.annotation
- base_type = get_origin(annotation) or annotation
-
- # Optional[Interval[float]] alias for Union[X, None]
- if base_type is Union:
- for arg in get_args(annotation):
- if arg is not NoneType:
- field_type = arg
- break
- else:
- field_type = base_type
-
- is_interval_float = (
- field_type == Interval[float]
- or str(field_type) == str(Interval[float])
- or "Interval[float]" in str(field_type)
- )
-
- if is_interval_float:
- label_text_start = " ".join([x.capitalize() for x in name.split("_")]) + " Start"
- label_text_end = " ".join([x.capitalize() for x in name.split("_")]) + " End"
- widget += f"""
-
- """
- elif issubclass(field_type, Enum):
- options: str = ""
- for e in field_type:
- options += f'
'
-
- label_text = " ".join([x.capitalize() for x in name.split("_")])
- widget += f"""
-
-
-
-
- """
- else:
- if field_type is str or field_type is HttpUrl:
- input_type = "text"
- elif field_type is float or field_type is int:
- input_type = "number"
- elif field_type is bool:
- input_type = "checkbox"
- else:
- raise ValueError(f"Could not parse field type {field_type} for {name}")
-
- value_to_use = value if value and field_type is not bool else ""
- label_text = " ".join([x.capitalize() for x in name.split("_")])
-
- if field_type is bool:
- widget += f"""
-
-
-
- """
- else:
- widget += f"""
-
-
-
-
- """
-
- return widget
-
- @staticmethod
- def build_models(params) -> Dict[str, List["EnviPyModel"]]:
- def has_non_none(d):
- """
- Recursively checks if any value in a (possibly nested) dict is not None.
- """
- for value in d.values():
- if isinstance(value, dict):
- if has_non_none(value): # recursive check
- return True
- elif value is not None:
- return True
- return False
-
- """
- Build Pydantic model instances from flattened HTML parameters.
-
- Args:
- params: dict of {param_name: value}, e.g. form data
- model_registry: mapping of class names (strings) to Pydantic model classes
-
- Returns:
- dict: {ClassName: [list of model instances]}
- """
- grouped: Dict[str, Dict[str, Dict[str, Any]]] = {}
-
- # Step 1: group fields by ClassName and Number
- for key, value in params.items():
- if value == "":
- value = None
-
- parts = key.split("__")
- if len(parts) < 3:
- continue # skip invalid keys
-
- class_name, number, *field_parts = parts
- grouped.setdefault(class_name, {}).setdefault(number, {})
-
- # handle nested fields like interval__start
- target = grouped[class_name][number]
- current = target
- for p in field_parts[:-1]:
- current = current.setdefault(p, {})
- current[field_parts[-1]] = value
-
- # Step 2: instantiate Pydantic models
- instances: Dict[str, List[BaseModel]] = defaultdict(list)
- for class_name, number_dict in grouped.items():
- model_cls = HTMLGenerator.registry.get(class_name)
-
- if not model_cls:
- logger.info(f"Could not find model class for {class_name}")
- continue
-
- for number, fields in number_dict.items():
- if not has_non_none(fields):
- print(f"Skipping empty {class_name} {number} {fields}")
- continue
-
- uuid = fields.pop("uuid", None)
- instance = model_cls(**fields)
- if uuid:
- instance.__dict__["uuid"] = uuid
- instances[class_name].append(instance)
-
- return instances
-
-
class PackageExporter:
def __init__(
self,
diff --git a/uv.lock b/uv.lock
index 094d26ea..c3769173 100644
--- a/uv.lock
+++ b/uv.lock
@@ -670,6 +670,7 @@ dependencies = [
{ name = "envipy-plugins" },
{ name = "epam-indigo" },
{ name = "gunicorn" },
+ { name = "jsonref" },
{ name = "networkx" },
{ name = "nh3" },
{ name = "polars" },
@@ -711,11 +712,12 @@ requires-dist = [
{ name = "django-polymorphic", specifier = ">=4.1.0" },
{ name = "django-stubs", marker = "extra == 'dev'", specifier = ">=5.2.4" },
{ name = "enviformer", git = "ssh://git@git.envipath.com/enviPath/enviformer.git?rev=v0.1.4" },
- { name = "envipy-additional-information", git = "ssh://git@git.envipath.com/enviPath/enviPy-additional-information.git?rev=v0.1.7" },
+ { name = "envipy-additional-information", git = "ssh://git@git.envipath.com/enviPath/enviPy-additional-information.git?rev=v0.2.0" },
{ name = "envipy-ambit", git = "ssh://git@git.envipath.com/enviPath/enviPy-ambit.git" },
{ name = "envipy-plugins", git = "ssh://git@git.envipath.com/enviPath/enviPy-plugins.git?rev=v0.1.0" },
{ name = "epam-indigo", specifier = ">=1.30.1" },
{ name = "gunicorn", specifier = ">=23.0.0" },
+ { name = "jsonref", specifier = ">=1.1.0" },
{ name = "msal", marker = "extra == 'ms-login'", specifier = ">=1.33.0" },
{ name = "networkx", specifier = ">=3.4.2" },
{ name = "nh3", specifier = "==0.3.2" },
@@ -739,8 +741,8 @@ provides-extras = ["ms-login", "dev"]
[[package]]
name = "envipy-additional-information"
-version = "0.1.7"
-source = { git = "ssh://git@git.envipath.com/enviPath/enviPy-additional-information.git?rev=v0.1.7#d02a5d5e6a931e6565ea86127813acf7e4b33a30" }
+version = "0.2.0"
+source = { git = "ssh://git@git.envipath.com/enviPath/enviPy-additional-information.git?rev=v0.2.0#02e3ae64b2ff42a5d2b723a76727c8f6755c9a90" }
dependencies = [
{ name = "pydantic" },
]
@@ -1015,6 +1017,15 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/72/68/84050ed2679e2d2ee2030a60d3e5a59a29d0533cd03fd8d9891e36592b0f/jpype1-1.6.0-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:1a3814e4f65d67e36bdb03b8851d5ece8d7a408aa3a24251ea0609bb8fba77dd", size = 497229, upload-time = "2025-07-07T13:50:57.842Z" },
]
+[[package]]
+name = "jsonref"
+version = "1.1.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/aa/0d/c1f3277e90ccdb50d33ed5ba1ec5b3f0a242ed8c1b1a85d3afeb68464dca/jsonref-1.1.0.tar.gz", hash = "sha256:32fe8e1d85af0fdefbebce950af85590b22b60f9e95443176adbde4e1ecea552", size = 8814, upload-time = "2023-01-16T16:10:04.455Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/0c/ec/e1db9922bceb168197a558a2b8c03a7963f1afe93517ddd3cf99f202f996/jsonref-1.1.0-py3-none-any.whl", hash = "sha256:590dc7773df6c21cbf948b5dac07a72a251db28b0238ceecce0a2abfa8ec30a9", size = 9425, upload-time = "2023-01-16T16:10:02.255Z" },
+]
+
[[package]]
name = "jwcrypto"
version = "1.5.6"