diff --git a/doc/source/serverless/caveats.rst b/doc/source/serverless/caveats.rst index 33a83c237..63c2e2e1e 100644 --- a/doc/source/serverless/caveats.rst +++ b/doc/source/serverless/caveats.rst @@ -87,20 +87,19 @@ Example: Threading with Serverless ADR for t in threads: t.join() -Common Pitfalls and Solutions ------------------------------ - -- **Error: "ADR has not been set up" in worker processes** - - _Cause_: ``ADR.setup()`` was not called in the worker process. - - _Solution_: Call ``adr.setup()`` early in each new process, as shown above. - -- **Race conditions or inconsistent state due to multiple ``setup()`` calls** - - _Cause_: Concurrent calls to ``setup()`` from multiple threads. +Serverless ADR Usage Within Django Apps +-------------------------------------- - _Solution_: Call ``setup()`` only once in the main thread before spawning workers. +- Serverless ADR internally configures Django settings and environment variables at the + process level during ``ADR.setup()``. +- Because Django settings are designed to be configured once per process, **attempting + to initialize Serverless ADR inside an existing Django application causes conflicts.** +- Specifically, setting up Serverless ADR tries to configure Django a second time, which + is unsupported and results in errors or unpredictable behavior. +- This means **embedding or using Serverless ADR as a Django app within another Django + project is not currently supported and strongly discouraged.** +- If you require integration, consider separating Serverless ADR usage into a dedicated + process or microservice to avoid Django settings conflicts. Summary and Best Practices -------------------------- @@ -109,7 +108,8 @@ Summary and Best Practices - In multiprocessing scenarios, call ``setup()`` separately in each spawned process. - Avoid calling ``setup()`` multiple times or concurrently within the same process. - Share the ADR instance across threads within a process after setup completes. +- Avoid embedding Serverless ADR within other Django apps due to Django configuration conflicts. - If unsure whether setup is needed, check ``adr.is_setup`` before calling. By following these guidelines, you ensure stable and consistent Serverless ADR usage -in complex multi-threaded or multi-process environments. +in complex multi-threaded or multi-process environments without risking Django conflicts. diff --git a/doc/source/serverless/configuration.rst b/doc/source/serverless/configuration.rst index 39c18b67e..b5516c24d 100644 --- a/doc/source/serverless/configuration.rst +++ b/doc/source/serverless/configuration.rst @@ -63,9 +63,15 @@ The primary configuration options for the ``ADR`` class constructor are: Environment Variables ===================== -Serverless ADR supports several environment variables to configure its runtime behavior, -database connections, security settings, and media/static file handling. These variables -can be used for legacy configurations or advanced deployments. +.. warning:: + + **Use of environment variables for Serverless ADR configuration is strongly discouraged.** + Environment variables represent a legacy configuration method and can lead to hidden, + hard-to-debug issues, security risks (such as leaking secrets), and inconsistent behavior + especially in multi-instance or containerized deployments. + + It is highly recommended to use explicit constructor parameters and configuration files + for all setup and runtime options instead. Core Variables -------------- @@ -86,17 +92,11 @@ Core Variables URL prefix used to access media files remotely. Must start and end with a slash, e.g., ``/media/``. Corresponds to the ``media_url`` constructor parameter. -- **CEI_NEXUS_LOCAL_ALLOW_REMOTE_ACCESS** - If set to any value, allows remote access to a local database server (use cautiously). - -- **CEI_NEXUS_SERVE_STATIC_FILES** - If ``True``, enables Django’s built-in static and media file serving (not recommended for production). - Database Connection Variables ----------------------------- - **CEI_NEXUS_DB_ENGINE** - Database engine string (e.g., ``django.db.backends.postgresql_psycopg2``). Defaults to PostgreSQL. + Database engine. Defaults to SQLite. - **CEI_NEXUS_DB_DATABASE_NAME** Name of the database to connect to. Defaults to ``nexus_database``. @@ -108,78 +108,29 @@ Database Connection Variables Password for the database user. Default is ``cei``. - **CEI_NEXUS_DB_HOSTNAME** - Database server hostname or IP address. Defaults to ``127.0.0.1``. + Database server hostname or IP address. Defaults to the path to the SQLite database file. - **CEI_NEXUS_DB_PORT** - Database server port number. Default is ``5432``. + Database server port number. Default is not set for SQLite. -Security and Server Variables ------------------------------ - -- **CEI_NEXUS_SERVER_NAME** - Human-readable name of the server. Defaults to ``mixed``. +Security Variables +------------------ - **CEI_NEXUS_SECRET_KEY** Django secret key used internally. If not provided, a built-in default key is used (not recommended for production). -- **CEI_NEXUS_ALLOWED_HOSTS** - Comma-separated list of allowed hostnames for accessing the server (e.g., ``localhost,127.0.0.1``). - -- **CEI_NEXUS_TRUSTED_ORIGINS** - List of trusted origins for unsafe requests like POST, supporting wildcards (e.g., ``https://*.example.com``). - -- **CEI_NEXUS_HTTPS_SECURED** - Boolean flag to indicate if the server runs behind HTTPS only. Enables security headers. - -- **CEI_NEXUS_HSTS_SECURED** - Enables HTTP Strict Transport Security (HSTS) headers. - -- **CEI_NEXUS_HSTS_SECONDS** - Duration in seconds for HSTS policy enforcement. Use with caution to avoid locking out clients. - -- **CEI_NEXUS_X_FRAME_OPTIONS** - Sets the HTTP X-Frame-Options header globally for protection against clickjacking. - Advanced / Optional Variables ----------------------------- - **CEI_NEXUS_ENABLE_ACLS** Enables per-category Access Control Lists (ACLs). Experimental and not recommended for general use. -- **CEI_NEXUS_ACLS_NGINX_LOCATION** - NGINX internal location directive for permission-protected media files. Default is ``/media_secured``. - -Remote Session Configuration ----------------------------- - -- **CEI_NEXUS_REMOTE_WEBSOCKETURL** - URL to the NGINX server proxying to the websocket server. - -- **CEI_NEXUS_REMOTE_WS_PORT** - Port used by the websocket server for WS protocol communication. - -- **CEI_NEXUS_REMOTE_HTML_PORT** - Port used by the websocket server for HTTP REST communication. - -- **CEI_NEXUS_REMOTE_VNCPASSWORD** - Password for VNC server sessions. - Usage Notes ----------- -- When running a non-debug local server, use the following command to enable static file serving: - - .. code-block:: bash +- Constructor parameters take precedence over environment variables. If both are set, constructor values will be used. - python manage.py runserver --insecure 0.0.0.0:8000 - -- Environment variables override constructor parameters if both are set. - -- Always set secure secret keys in production environments to protect sensitive data. - -- Configure ``CEI_NEXUS_ALLOWED_HOSTS`` and ``CEI_NEXUS_TRUSTED_ORIGINS`` to restrict server access. - -- When enabling HTTPS and HSTS, be cautious with duration settings to avoid client lockout. +- Always set secure secret keys in production environments to protect sensitive data. If you do not set a key, a default will be used. Example: Setting environment variables in Linux shell: @@ -189,8 +140,6 @@ Example: Setting environment variables in Linux shell: export CEI_NEXUS_LOCAL_MEDIA_DIR="/var/data/adr_media" export CEI_NEXUS_MEDIA_URL_PREFIX="/media/" export CEI_NEXUS_SECRET_KEY="a-very-secure-secret-key" - export CEI_NEXUS_ALLOWED_HOSTS="localhost,127.0.0.1" - export CEI_NEXUS_HTTPS_SECURED="True" Example: Passing variables via ``opts`` parameter: @@ -206,14 +155,6 @@ Example: Passing variables via ``opts`` parameter: adr = ADR(ansys_installation="/opt/ansys", opts=opts) adr.setup() -Summary -------- - -Proper use of environment variables allows flexible deployment and integration of Serverless ADR -into diverse environments, including containerized, cloud, or on-premises infrastructures. - -See also the :doc:`configuration` and :doc:`setup` guides for comprehensive initialization instructions. - **Note: Prefer constructor parameters for new projects. Environment variables remain supported primarily for legacy compatibility.** Best Practices @@ -252,50 +193,6 @@ Examples ) adr.setup(collect_static=True) -**Multi-database PostgreSQL and SQLite setup:** - -.. code-block:: python - - database_config = { - "default": { - "ENGINE": "postgresql", - "NAME": "adr_db", - "USER": "adr_user", - "PASSWORD": "password", - "HOST": "localhost", - "PORT": "5432", - }, - "sqlite_local": { - "ENGINE": "sqlite3", - "NAME": r"C:\Reports\DB\local.sqlite3", - }, - } - - adr = ADR( - ansys_installation=r"/opt/ansys", - databases=database_config, - media_directory=r"/opt/reports/media", - static_directory=r"/opt/reports/static", - media_url="/media/", - static_url="/static/", - ) - adr.setup() - -**Docker-based Ansys installation:** - -.. code-block:: python - - adr = ADR( - ansys_installation="docker", - docker_image="ghcr.io/ansys-internal/nexus_dev", - db_directory=r"C:\Reports\DB", - media_directory=r"C:\Reports\Media", - static_directory=r"C:\Reports\Static", - media_url="/media/", - static_url="/static/", - ) - adr.setup() - Troubleshooting --------------- @@ -312,11 +209,5 @@ Troubleshooting Summary ------- -Proper configuration of Serverless ADR ensures seamless database connections, media management, and web serving of report assets. Follow best practices for setup and environment initialization to avoid common issues. - -Next Steps ----------- - -See the :doc:`setup` guide for detailed startup and initialization instructions. - -See the :doc:`media_and_static` guide for managing static and media files in your reports. +Proper configuration of Serverless ADR ensures seamless database connections, media management, and web serving of report assets. +Follow best practices for setup and environment initialization to avoid common issues. diff --git a/doc/source/serverless/copying_objects.rst b/doc/source/serverless/copying_objects.rst index bc8d68d85..08d51c9c3 100644 --- a/doc/source/serverless/copying_objects.rst +++ b/doc/source/serverless/copying_objects.rst @@ -134,7 +134,7 @@ Best Practices -------------- - Ensure the target database is properly configured and accessible before copying. -- Copy related sessions and datasets automatically by copying items or templates. +- Copy related sessions and datasets automatically by copying items. - Always use ``test=True`` initially to preview the number of objects to be copied. - Ensure media directories have sufficient space and permissions. - Use descriptive ADR query strings to limit copy scope. diff --git a/doc/source/serverless/embedding_reports.rst b/doc/source/serverless/embedding_reports.rst index f907e40a2..531ed2871 100644 --- a/doc/source/serverless/embedding_reports.rst +++ b/doc/source/serverless/embedding_reports.rst @@ -21,7 +21,7 @@ Generating Embed-Ready HTML --------------------------- Use the ``render_report()`` method of the ADR instance to render a complete -report or a subset of it as HTML. +report. .. code-block:: python @@ -42,8 +42,6 @@ You can also render individual report items using their ``render()`` method: .. code-block:: python item = adr.create_item(String, name="summary_text", content="Summary content here.") - item.save() - html_snippet = item.render(context={"plotly": 0}) Embedding Partial Templates or Sections @@ -63,7 +61,7 @@ Integration Tips - Make sure your embedded HTML includes references to static and media URLs configured during ADR setup so that assets like images and stylesheets - load correctly. + load correctly and your web server is configured to serve them. - Use the ``context`` parameter to pass additional context variables needed for rendering. @@ -81,6 +79,7 @@ Example with Flask: .. code-block:: python + from ansys.dynamicreporting.core.serverless import ADR from flask import Flask, render_template_string app = Flask(__name__) @@ -88,8 +87,6 @@ Example with Flask: @app.route("/embedded-report") def embedded_report(): - from ansys.dynamicreporting.core.serverless import ADR - adr = ADR.get_instance() my_app_html = "" html = adr.render_report(name="My Simulation Report") @@ -112,7 +109,7 @@ Security Considerations - Validate and sanitize any dynamic input used in filters or templates to avoid injection attacks. -- Limit exposure of internal data by controlling which templates or items +- Limit exposure of data by controlling which templates or items are accessible for embedding. Summary diff --git a/doc/source/serverless/examples.rst b/doc/source/serverless/examples.rst index e69de29bb..ce68152a0 100644 --- a/doc/source/serverless/examples.rst +++ b/doc/source/serverless/examples.rst @@ -0,0 +1,3 @@ +Examples +======== + diff --git a/doc/source/serverless/index.rst b/doc/source/serverless/index.rst index 7800c128a..3d3636c0d 100644 --- a/doc/source/serverless/index.rst +++ b/doc/source/serverless/index.rst @@ -19,15 +19,14 @@ want to: - Create, manage, and render reports locally using Python - Avoid setting up a centralized ADR service or HTTP connection -- Maintain full fidelity with the ADR schema (items, templates, layout logic) -- Output HTML content and media assets for web apps, automation, or - documentation pipelines +- Maintain full fidelity with the ADR schema (items, templates, etc.) +- Output HTML content and media assets for web and desktop apps. Serverless ADR is ideal for: - Local, file-based workflows (e.g., building offline reports) +- Embedding reports in web or desktop applications - Use in batch scripts, Python notebooks, or simulations -- Building and verifying templates before pushing to production ADR services Key features ============ diff --git a/doc/source/serverless/items.rst b/doc/source/serverless/items.rst index 558246c4f..0f5cb8936 100644 --- a/doc/source/serverless/items.rst +++ b/doc/source/serverless/items.rst @@ -41,7 +41,6 @@ Items automatically link to the current default session and dataset unless speci content="This simulation demonstrates fluid flow around a wing.", tags="section=summary project=wing_sim", ) - string_item.save() # Create a table item with data data = np.array( @@ -71,7 +70,10 @@ Item Properties and Metadata Items support several useful properties and metadata fields: +- **guid**: Unique identifier for the item, automatically generated. - **name**: Unique identifier for the item within the dataset. +- **type**: The item type (e.g., `string`, `table`, etc.). +- **date**: Timestamp indicating when the item was created. - **content**: The primary payload of the item, type-dependent. - **tags**: A space-separated string of key or key=value tags for querying and filtering. - **source**: String to track the data origin or generating process. @@ -94,7 +96,6 @@ Example: Creating and saving an image item content="path/to/wing_profile.png", tags="section=images project=wing_sim", ) - image_item.save() After saving, the file is copied into the configured media directory. You can access the uploaded file's storage path using the `file_path` property: @@ -106,7 +107,8 @@ After saving, the file is copied into the configured media directory. You can ac This path points to the location within the media directory configured during ADR setup. You can use this path for verification, further processing, or serving the media file in your application. -When rendering reports or templates that include media items, the HTML references media files using relative URLs, typically prefixed by the configured media URL (default is `/media/`): +When rendering reports or templates that include media items, the HTML references media files using relative URLs, +typically prefixed by the configured media URL (default is `/media/`): .. code-block:: html @@ -118,7 +120,10 @@ Ensure your web server is configured to serve these media URLs from the media di Summary: - Set the `content` of file-based items to the local file path before saving. - After saving, `file_path` gives the full path to the uploaded media file. +- When the item is loaded again from the database, `content` will be the relative path to the media file. - Rendered reports use relative media URLs; configure your web server accordingly. +- Use the `media_url` property to get the URL prefix for serving media files. +- The media URL is typically `/media/` by default. Rendering Items --------------- diff --git a/doc/source/serverless/media_and_static.rst b/doc/source/serverless/media_and_static.rst index 778a1dc99..36d513d98 100644 --- a/doc/source/serverless/media_and_static.rst +++ b/doc/source/serverless/media_and_static.rst @@ -3,7 +3,7 @@ Media and Static Files Serverless ADR manages two key asset categories essential for rich report presentation: -- **Media files**: User-uploaded or generated files such as images, animations, 3D models, and other payloads associated with Items. +- **Media files**: User-uploaded or generated files such as images, animations, 3D models, and other content associated with Items. - **Static files**: Framework assets including CSS, JavaScript, fonts, and icons required to render reports and web interfaces correctly. This guide covers the storage, access, lifecycle, and best practices for managing these files in Serverless ADR. @@ -64,7 +64,6 @@ File Storage and Access ----------------------- - Media files are saved with unique names based on the Item GUID and type, e.g., ``_image.png``. -- Items with associated files use the ``FilePayloadMixin`` to manage file storage and retrieval. - The media directory should be accessible by any server or process serving reports or web content. - Static files are collected during setup if ``collect_static=True`` is passed to ``ADR.setup()``. - Static files can be served by any compatible web server (eg. NGINX) or via built-in mechanisms in web frameworks. @@ -100,7 +99,6 @@ Example: Creating and saving an Image Item with a file content="C:\\images\\wing_profile.png", tags="section=geometry", ) - img_item.save() Working with Media Files Directly -------------------------------- @@ -130,6 +128,7 @@ Static Files Collection and Serving - Static files are typically collected from ADR’s installed packages during setup by calling: ``adr.setup(collect_static=True)`` + - This process copies necessary CSS, JS, fonts, and icons into the configured static directory. - Static files must be served by your web server or framework to enable proper report rendering. - The static URL prefix (e.g., ``/static/``) must correspond to your web server configuration. @@ -138,8 +137,8 @@ In-Memory Mode and Temporary Files ---------------------------------- - When using ADR in in-memory mode (``in_memory=True``), media and static files are stored in temporary directories. -- These directories are automatically cleaned up when ADR closes, so media files do not persist beyond the session. -- This mode is useful for testing or transient report generation but not for production. +- These directories are automatically cleaned up when ADR closes, so files do not persist beyond the session. +- This mode is useful for testing or transient report generation. Best Practices -------------- diff --git a/doc/source/serverless/overview.rst b/doc/source/serverless/overview.rst index 7fa5db570..8c5ed62d8 100644 --- a/doc/source/serverless/overview.rst +++ b/doc/source/serverless/overview.rst @@ -10,7 +10,7 @@ Key Benefits - Runs entirely within your Python process — no external server needed. - Supports both SQLite and PostgreSQL databases. - Uses the same core schema as the traditional ADR service. -- Enables offline report generation with full fidelity (items, templates, layouts). +- Enables offline report generation with full fidelity (items, templates, etc.). - Suitable for local workflows, batch processing, and embedding in Python applications. - Fully backwards compatible with the service-based ADR API. diff --git a/doc/source/serverless/querying.rst b/doc/source/serverless/querying.rst index ae61d249a..1357b76d4 100644 --- a/doc/source/serverless/querying.rst +++ b/doc/source/serverless/querying.rst @@ -60,13 +60,14 @@ Examples matching_items = Item.find(query=query_str) print(f"Found {len(matching_items)} matching items") -**Use the static ADR query method to find Sessions with a name:** +**Use the ADR query method to find Sessions with a name:** .. code-block:: python from ansys.dynamicreporting.core.serverless import ADR, Session - sessions = ADR.query(Session, query="A|s_name|eq|Test Session;") + adr = ADR.get_instance() + sessions = adr.query(Session, query="A|s_name|eq|Test Session;") for s in sessions: print(s.guid, s.date) @@ -138,7 +139,7 @@ Working with Query Results -------------------------- - ``get()`` returns a single model instance. -- ``filter()``, ``find()``, and ``ADR.query()`` return an ``ObjectSet`` that behaves like a list. +- ``filter()``, ``find()``, and ``ADR.query()`` return an ``ObjectSet`` that behaves like a list and can be cast to a list or iterated over. You can iterate over results, use ``len()``, or index them: @@ -175,7 +176,6 @@ Summary Querying in Serverless ADR allows precise and flexible data retrieval using: - Field filters for common attributes -- Tag substring filters - Powerful ADR query language strings - Subclass-specific automatic type filtering diff --git a/doc/source/serverless/quickstart.rst b/doc/source/serverless/quickstart.rst index 365bdb801..fe46a1d63 100644 --- a/doc/source/serverless/quickstart.rst +++ b/doc/source/serverless/quickstart.rst @@ -35,7 +35,6 @@ Create report items such as text or tables tied to the default session and datas tags="section=intro", source="quickstart-example", ) - item.save() Building Templates ------------------ diff --git a/doc/source/serverless/sessions_and_datasets.rst b/doc/source/serverless/sessions_and_datasets.rst index 8f7b3e7a1..93c5b9825 100644 --- a/doc/source/serverless/sessions_and_datasets.rst +++ b/doc/source/serverless/sessions_and_datasets.rst @@ -8,8 +8,7 @@ In this API, a **Session** represents a logical grouping or “push” of data f (such as a solver or post-processor) into the ADR system. It captures metadata about when, where, and how the data was ingested. -A **Dataset** contains the actual simulation or analysis data associated with a Session. This could -include files, tables, images, or other artifacts generated during the simulation. +A **Dataset** contains the metadata about actual simulation or analysis data associated with a Session. By associating report items with Sessions and Datasets, the API maintains clear context and provenance, enabling organized, meaningful reports that trace back to the original data source. @@ -20,10 +19,9 @@ flexible and efficient report generation workflows. Key Entities ------------ -- **Session**: Stores metadata about the session or logical grouping of data imported into ADR during a single -data push or analysis run, such as date, hostname, platform, and application version. -- **Dataset**: Stores metadata about the dataset or collection of simulation or analysis data, such as files, -formats, and element counts. +- **Session**: Stores metadata about the session or logical grouping of data imported into ADR during a single data push or analysis run, such as date, hostname, platform, and application version. + +- **Dataset**: Stores metadata about the dataset or collection of simulation or analysis data, such as files, formats, and element counts. Session and Dataset Properties and Metadata ------------------------------------------- @@ -31,21 +29,35 @@ Session and Dataset Properties and Metadata Sessions and Datasets include important properties and metadata fields that help organize and contextualize your data: - **Session properties:** + - **guid**: Unique identifier for the session. + - **date**: Timestamp of when the session was created or recorded. + - **hostname**: The machine or environment where the data push originated. + - **platform**: Operating system or platform information. + - **application**: Name of the application or tool that created the session. + - **version**: Version of the application or tool. + - **tags**: Space-separated string of key or key=value tags for filtering and classification. - **Dataset properties:** + - **guid**: Unique identifier for the dataset. + - **filename**: Name of the data file associated with the dataset. + - **dirname**: Directory path or location related to the dataset. + - **format**: Data format descriptor (e.g., CDB, CSV). + - **numparts**: Number of parts or segments in the dataset. + - **numelements**: Number of elements (e.g., mesh elements) in the dataset. + - **tags**: Space-separated string of key or key=value tags for filtering and classification. Both Sessions and Datasets play a key role in associating your report items with the proper data context and provenance. @@ -139,7 +151,7 @@ Exceptions and Validation - Creating or modifying sessions and datasets will raise errors if required fields are missing or invalid. -- Querying items with incorrect syntax or unsupported operations raises an `ADRException`. +- Querying items with incorrect syntax or unsupported operations raises an ``ADRException``. - Fetching non-existent sessions or datasets by GUID raises a ``DoesNotExist`` error. - Multiple objects returned for a single fetch raises a ``MultipleObjectsReturned`` error. diff --git a/doc/source/serverless/templates.rst b/doc/source/serverless/templates.rst index c0f85fff0..ce36f1bbf 100644 --- a/doc/source/serverless/templates.rst +++ b/doc/source/serverless/templates.rst @@ -78,7 +78,10 @@ Template Attributes and Methods Templates have several important properties and methods: +- ``guid``: Unique identifier for the template. - ``name``: The template’s unique name. +- ``date``: The date when the template was created. +- ``tags``: A string of tags for categorization and filtering. - ``params``: JSON-encoded string storing rendering parameters and properties. - ``item_filter``: Query string filter to select items included in this template. - ``parent``: Reference to the parent template or None for root templates. @@ -102,11 +105,11 @@ Template Parameters Each template stores configuration and state in its ``params`` field, a JSON string representing: -- HTML content or raw strings (e.g., ``"HTML"``) +- HTML header (e.g., ``"HTML"``) - Layout-specific options (e.g., column counts, widths) - Filter parameters and modes controlling which Items are included - Sorting options (fields, order, selection) -- Custom properties for configuration and behavior +- Other custom properties for configuration and behavior You can manipulate these through provided methods: @@ -282,10 +285,6 @@ Example: Creating a Nested Template Structure results_panel.set_filter("A|i_tags|cont|section=results;") results_panel.save() - top_template.children.append(results_panel) - top_template.save() - - Rendering Templates ------------------ @@ -319,7 +318,6 @@ Lifecycle Notes - Templates must be saved to persist changes. - Parent templates must be saved before saving children. -- Children templates must be saved before their parent saves can complete successfully. - Deleting a template typically requires handling or deleting its children to avoid orphaned templates. Exceptions and Validation @@ -327,7 +325,7 @@ Exceptions and Validation - Creating or fetching templates with missing or invalid fields raises validation errors. - Attempting to instantiate the base ``Template`` class directly raises an error. -- Filters using restricted keys (like ``t_types|``) are disallowed on subclasses. +- Filters using keys mentioning the type (like ``t_types|``) are disallowed on subclasses. - Invalid parent references or child types will raise type or integrity errors during saving. - Only top-level templates (parent=None) can be copied between databases. - Templates must have their parents and children saved before saving themselves to ensure integrity. @@ -341,6 +339,3 @@ Summary Templates are the backbone of report structure in Serverless ADR. They let you create rich, dynamic, and highly customizable reports by defining layouts and generators, setting filters and parameters, and nesting templates to build complex hierarchical reports. - -Next, move on to the :doc:`rendering` guide to learn how to convert templates and items -into final HTML reports for presentation or web serving. diff --git a/pyproject.toml b/pyproject.toml index c6ad5dc54..5321e8f1f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -44,6 +44,7 @@ dependencies = [ "python-pptx==0.6.19", "pandas>=2.0", "statsmodels>=0.14", + "scipy<=1.15.3", # breaks ADR if not included. Remove when statsmodels is updated "docutils>=0.21", "psycopg[binary]>=3.2.3", ]