processforge 0.3.9__tar.gz → 0.3.10__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {processforge-0.3.9/src/processforge.egg-info → processforge-0.3.10}/PKG-INFO +2 -1
- {processforge-0.3.9 → processforge-0.3.10}/pyproject.toml +2 -1
- {processforge-0.3.9 → processforge-0.3.10}/src/processforge/api/serve.py +22 -0
- {processforge-0.3.9 → processforge-0.3.10}/src/processforge/cli/run.py +4 -0
- {processforge-0.3.9 → processforge-0.3.10}/src/processforge/providers/container_client.py +2 -2
- processforge-0.3.10/src/processforge/utils/s3_upload.py +69 -0
- {processforge-0.3.9 → processforge-0.3.10/src/processforge.egg-info}/PKG-INFO +2 -1
- {processforge-0.3.9 → processforge-0.3.10}/src/processforge.egg-info/SOURCES.txt +2 -0
- {processforge-0.3.9 → processforge-0.3.10}/src/processforge.egg-info/requires.txt +1 -0
- processforge-0.3.10/tests/test_s3_upload.py +81 -0
- {processforge-0.3.9 → processforge-0.3.10}/LICENSE +0 -0
- {processforge-0.3.9 → processforge-0.3.10}/MANIFEST.in +0 -0
- {processforge-0.3.9 → processforge-0.3.10}/README.md +0 -0
- {processforge-0.3.9 → processforge-0.3.10}/flowsheets/closed-loop-chain.json +0 -0
- {processforge-0.3.9 → processforge-0.3.10}/flowsheets/custom/crimson/MUWS_HB.json +0 -0
- {processforge-0.3.9 → processforge-0.3.10}/flowsheets/custom/simple_hyrdaulic_scheme.json +0 -0
- {processforge-0.3.9 → processforge-0.3.10}/flowsheets/festim/hydrogen_transport_1d.json +0 -0
- {processforge-0.3.9 → processforge-0.3.10}/flowsheets/hydraulic-chain.json +0 -0
- {processforge-0.3.9 → processforge-0.3.10}/flowsheets/openmc/msre_eigenvalue.json +0 -0
- {processforge-0.3.9 → processforge-0.3.10}/setup.cfg +0 -0
- {processforge-0.3.9 → processforge-0.3.10}/src/processforge/__init__.py +0 -0
- {processforge-0.3.9 → processforge-0.3.10}/src/processforge/__main__.py +0 -0
- {processforge-0.3.9 → processforge-0.3.10}/src/processforge/_schema.py +0 -0
- {processforge-0.3.9 → processforge-0.3.10}/src/processforge/analysis/__init__.py +0 -0
- {processforge-0.3.9 → processforge-0.3.10}/src/processforge/analysis/dof.py +0 -0
- {processforge-0.3.9 → processforge-0.3.10}/src/processforge/api/__init__.py +0 -0
- {processforge-0.3.9 → processforge-0.3.10}/src/processforge/cli/__init__.py +0 -0
- {processforge-0.3.9 → processforge-0.3.10}/src/processforge/cli/apply.py +0 -0
- {processforge-0.3.9 → processforge-0.3.10}/src/processforge/cli/common.py +0 -0
- {processforge-0.3.9 → processforge-0.3.10}/src/processforge/cli/diagram.py +0 -0
- {processforge-0.3.9 → processforge-0.3.10}/src/processforge/cli/display.py +0 -0
- {processforge-0.3.9 → processforge-0.3.10}/src/processforge/cli/export_fmu.py +0 -0
- {processforge-0.3.9 → processforge-0.3.10}/src/processforge/cli/export_modelica.py +0 -0
- {processforge-0.3.9 → processforge-0.3.10}/src/processforge/cli/init.py +0 -0
- {processforge-0.3.9 → processforge-0.3.10}/src/processforge/cli/plan.py +0 -0
- {processforge-0.3.9 → processforge-0.3.10}/src/processforge/cli/validate.py +0 -0
- {processforge-0.3.9 → processforge-0.3.10}/src/processforge/compose.py +0 -0
- {processforge-0.3.9 → processforge-0.3.10}/src/processforge/eo/__init__.py +0 -0
- {processforge-0.3.9 → processforge-0.3.10}/src/processforge/eo/backends/__init__.py +0 -0
- {processforge-0.3.9 → processforge-0.3.10}/src/processforge/eo/backends/base.py +0 -0
- {processforge-0.3.9 → processforge-0.3.10}/src/processforge/eo/backends/casadi_backend.py +0 -0
- {processforge-0.3.9 → processforge-0.3.10}/src/processforge/eo/backends/pyomo_backend.py +0 -0
- {processforge-0.3.9 → processforge-0.3.10}/src/processforge/eo/backends/scipy_backend.py +0 -0
- {processforge-0.3.9 → processforge-0.3.10}/src/processforge/eo/flowsheet.py +0 -0
- {processforge-0.3.9 → processforge-0.3.10}/src/processforge/eo/jacobian.py +0 -0
- {processforge-0.3.9 → processforge-0.3.10}/src/processforge/eo/mixin.py +0 -0
- {processforge-0.3.9 → processforge-0.3.10}/src/processforge/eo/solver.py +0 -0
- {processforge-0.3.9 → processforge-0.3.10}/src/processforge/eo/stream_var.py +0 -0
- {processforge-0.3.9 → processforge-0.3.10}/src/processforge/eo/units/__init__.py +0 -0
- {processforge-0.3.9 → processforge-0.3.10}/src/processforge/eo/units/flash_eo.py +0 -0
- {processforge-0.3.9 → processforge-0.3.10}/src/processforge/eo/units/heater_eo.py +0 -0
- {processforge-0.3.9 → processforge-0.3.10}/src/processforge/eo/units/pipes_eo.py +0 -0
- {processforge-0.3.9 → processforge-0.3.10}/src/processforge/eo/units/pump_eo.py +0 -0
- {processforge-0.3.9 → processforge-0.3.10}/src/processforge/eo/units/strainer_eo.py +0 -0
- {processforge-0.3.9 → processforge-0.3.10}/src/processforge/eo/units/valve_eo.py +0 -0
- {processforge-0.3.9 → processforge-0.3.10}/src/processforge/flowsheet.py +0 -0
- {processforge-0.3.9 → processforge-0.3.10}/src/processforge/fmu/__init__.py +0 -0
- {processforge-0.3.9 → processforge-0.3.10}/src/processforge/fmu/_fmi_vars.py +0 -0
- {processforge-0.3.9 → processforge-0.3.10}/src/processforge/fmu/builder.py +0 -0
- {processforge-0.3.9 → processforge-0.3.10}/src/processforge/fmu/slave_template.py +0 -0
- {processforge-0.3.9 → processforge-0.3.10}/src/processforge/lock.py +0 -0
- {processforge-0.3.9 → processforge-0.3.10}/src/processforge/modelica/__init__.py +0 -0
- {processforge-0.3.9 → processforge-0.3.10}/src/processforge/modelica/mo_writer.py +0 -0
- {processforge-0.3.9 → processforge-0.3.10}/src/processforge/modelica/omc_runner.py +0 -0
- {processforge-0.3.9 → processforge-0.3.10}/src/processforge/modelica/transpiler.py +0 -0
- {processforge-0.3.9 → processforge-0.3.10}/src/processforge/modelica/unit_equations.py +0 -0
- {processforge-0.3.9 → processforge-0.3.10}/src/processforge/pcl/__init__.py +0 -0
- {processforge-0.3.9 → processforge-0.3.10}/src/processforge/pcl/compiler.py +0 -0
- {processforge-0.3.9 → processforge-0.3.10}/src/processforge/pcl/namespace.py +0 -0
- {processforge-0.3.9 → processforge-0.3.10}/src/processforge/provenance.py +0 -0
- {processforge-0.3.9 → processforge-0.3.10}/src/processforge/providers/__init__.py +0 -0
- {processforge-0.3.9 → processforge-0.3.10}/src/processforge/providers/base.py +0 -0
- {processforge-0.3.9 → processforge-0.3.10}/src/processforge/providers/base_jacobian_mixin.py +0 -0
- {processforge-0.3.9 → processforge-0.3.10}/src/processforge/providers/cantera_jacobian.py +0 -0
- {processforge-0.3.9 → processforge-0.3.10}/src/processforge/providers/cantera_provider.py +0 -0
- {processforge-0.3.9 → processforge-0.3.10}/src/processforge/providers/coolprop_provider.py +0 -0
- {processforge-0.3.9 → processforge-0.3.10}/src/processforge/providers/festim_provider.py +0 -0
- {processforge-0.3.9 → processforge-0.3.10}/src/processforge/providers/jacobian_contributor.py +0 -0
- {processforge-0.3.9 → processforge-0.3.10}/src/processforge/providers/manager.py +0 -0
- {processforge-0.3.9 → processforge-0.3.10}/src/processforge/providers/modelica_jacobian.py +0 -0
- {processforge-0.3.9 → processforge-0.3.10}/src/processforge/providers/modelica_provider.py +0 -0
- {processforge-0.3.9 → processforge-0.3.10}/src/processforge/providers/openmc_provider.py +0 -0
- {processforge-0.3.9 → processforge-0.3.10}/src/processforge/providers/reference_state_registry.py +0 -0
- {processforge-0.3.9 → processforge-0.3.10}/src/processforge/providers/registry.py +0 -0
- {processforge-0.3.9 → processforge-0.3.10}/src/processforge/result.py +0 -0
- {processforge-0.3.9 → processforge-0.3.10}/src/processforge/result_schema.py +0 -0
- {processforge-0.3.9 → processforge-0.3.10}/src/processforge/schemas/__init__.py +0 -0
- {processforge-0.3.9 → processforge-0.3.10}/src/processforge/schemas/flowsheet_schema.json +0 -0
- {processforge-0.3.9 → processforge-0.3.10}/src/processforge/schemas/openmc/openmc_model.py +0 -0
- {processforge-0.3.9 → processforge-0.3.10}/src/processforge/simulate.py +0 -0
- {processforge-0.3.9 → processforge-0.3.10}/src/processforge/solver.py +0 -0
- {processforge-0.3.9 → processforge-0.3.10}/src/processforge/state.py +0 -0
- {processforge-0.3.9 → processforge-0.3.10}/src/processforge/thermo.py +0 -0
- {processforge-0.3.9 → processforge-0.3.10}/src/processforge/types.py +0 -0
- {processforge-0.3.9 → processforge-0.3.10}/src/processforge/units/__init__.py +0 -0
- {processforge-0.3.9 → processforge-0.3.10}/src/processforge/units/base.py +0 -0
- {processforge-0.3.9 → processforge-0.3.10}/src/processforge/units/cstr.py +0 -0
- {processforge-0.3.9 → processforge-0.3.10}/src/processforge/units/flash.py +0 -0
- {processforge-0.3.9 → processforge-0.3.10}/src/processforge/units/heater.py +0 -0
- {processforge-0.3.9 → processforge-0.3.10}/src/processforge/units/pfr.py +0 -0
- {processforge-0.3.9 → processforge-0.3.10}/src/processforge/units/pipes.py +0 -0
- {processforge-0.3.9 → processforge-0.3.10}/src/processforge/units/pump.py +0 -0
- {processforge-0.3.9 → processforge-0.3.10}/src/processforge/units/registry.py +0 -0
- {processforge-0.3.9 → processforge-0.3.10}/src/processforge/units/solver_unit.py +0 -0
- {processforge-0.3.9 → processforge-0.3.10}/src/processforge/units/strainer.py +0 -0
- {processforge-0.3.9 → processforge-0.3.10}/src/processforge/units/tank.py +0 -0
- {processforge-0.3.9 → processforge-0.3.10}/src/processforge/units/valve.py +0 -0
- {processforge-0.3.9 → processforge-0.3.10}/src/processforge/utils/__init__.py +0 -0
- {processforge-0.3.9 → processforge-0.3.10}/src/processforge/utils/flowsheet_diagram.py +0 -0
- {processforge-0.3.9 → processforge-0.3.10}/src/processforge/utils/mermaid_diagram.py +0 -0
- {processforge-0.3.9 → processforge-0.3.10}/src/processforge/utils/topology.py +0 -0
- {processforge-0.3.9 → processforge-0.3.10}/src/processforge/utils/unit_consistency.py +0 -0
- {processforge-0.3.9 → processforge-0.3.10}/src/processforge/utils/validate_flowsheet.py +0 -0
- {processforge-0.3.9 → processforge-0.3.10}/src/processforge/utils/validation.py +0 -0
- {processforge-0.3.9 → processforge-0.3.10}/src/processforge.egg-info/dependency_links.txt +0 -0
- {processforge-0.3.9 → processforge-0.3.10}/src/processforge.egg-info/entry_points.txt +0 -0
- {processforge-0.3.9 → processforge-0.3.10}/src/processforge.egg-info/top_level.txt +0 -0
- {processforge-0.3.9 → processforge-0.3.10}/tests/test_cli.py +0 -0
- {processforge-0.3.9 → processforge-0.3.10}/tests/test_festim_provider.py +0 -0
- {processforge-0.3.9 → processforge-0.3.10}/tests/test_init.py +0 -0
- {processforge-0.3.9 → processforge-0.3.10}/tests/test_providers.py +0 -0
- {processforge-0.3.9 → processforge-0.3.10}/tests/test_state.py +0 -0
- {processforge-0.3.9 → processforge-0.3.10}/tests/test_types.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: processforge
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.10
|
|
4
4
|
Summary: A Python-based process simulation framework for chemical engineering applications.
|
|
5
5
|
Author-email: Processforge Team <team@processforge.dev>
|
|
6
6
|
License-Expression: BSD-3-Clause
|
|
@@ -33,6 +33,7 @@ Requires-Dist: typer>=0.12
|
|
|
33
33
|
Provides-Extra: api
|
|
34
34
|
Requires-Dist: fastapi>=0.110; extra == "api"
|
|
35
35
|
Requires-Dist: uvicorn>=0.29; extra == "api"
|
|
36
|
+
Requires-Dist: s3fs>=2024.0; extra == "api"
|
|
36
37
|
Provides-Extra: eo
|
|
37
38
|
Requires-Dist: pyomo>=6.7; extra == "eo"
|
|
38
39
|
Provides-Extra: eo-casadi
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "processforge"
|
|
7
|
-
version = "0.3.
|
|
7
|
+
version = "0.3.10"
|
|
8
8
|
description = "A Python-based process simulation framework for chemical engineering applications."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = "BSD-3-Clause"
|
|
@@ -42,6 +42,7 @@ dependencies = [
|
|
|
42
42
|
api = [
|
|
43
43
|
"fastapi>=0.110",
|
|
44
44
|
"uvicorn>=0.29",
|
|
45
|
+
"s3fs>=2024.0",
|
|
45
46
|
]
|
|
46
47
|
eo = [
|
|
47
48
|
"pyomo>=6.7",
|
|
@@ -15,6 +15,7 @@ import os
|
|
|
15
15
|
import traceback
|
|
16
16
|
|
|
17
17
|
from fastapi import FastAPI, HTTPException
|
|
18
|
+
from loguru import logger
|
|
18
19
|
|
|
19
20
|
app = FastAPI(title="Processforge Provider")
|
|
20
21
|
|
|
@@ -76,6 +77,7 @@ def run(body: dict):
|
|
|
76
77
|
try:
|
|
77
78
|
provider.initialize(provider_config, flowsheet_config)
|
|
78
79
|
result = provider.run_simulation(unit_cfg, body.get("inlet", {}))
|
|
80
|
+
_maybe_upload_run_outputs(result)
|
|
79
81
|
return result.as_dict() | {"metadata": result.metadata}
|
|
80
82
|
except HTTPException:
|
|
81
83
|
raise
|
|
@@ -88,6 +90,26 @@ def run(body: dict):
|
|
|
88
90
|
provider.teardown()
|
|
89
91
|
|
|
90
92
|
|
|
93
|
+
def _maybe_upload_run_outputs(result) -> None:
|
|
94
|
+
"""Upload the provider's run_dir to S3 when configured.
|
|
95
|
+
|
|
96
|
+
No-op unless ``S3_BUCKET`` is set in the container environment and the
|
|
97
|
+
provider recorded a ``run_dir`` in its result metadata. Upload failures are
|
|
98
|
+
logged and never fail the run.
|
|
99
|
+
"""
|
|
100
|
+
run_dir = result.metadata.get("run_dir")
|
|
101
|
+
if not run_dir:
|
|
102
|
+
return
|
|
103
|
+
try:
|
|
104
|
+
from processforge.utils.s3_upload import upload_directory_to_s3
|
|
105
|
+
|
|
106
|
+
s3_uri = upload_directory_to_s3(run_dir)
|
|
107
|
+
if s3_uri:
|
|
108
|
+
result.metadata["s3_uri"] = s3_uri
|
|
109
|
+
except Exception as exc: # noqa: BLE001
|
|
110
|
+
logger.warning(f"S3 upload of {run_dir} failed: {exc}")
|
|
111
|
+
|
|
112
|
+
|
|
91
113
|
if __name__ == "__main__":
|
|
92
114
|
import uvicorn
|
|
93
115
|
|
|
@@ -100,6 +100,10 @@ def run(
|
|
|
100
100
|
logger.info(f" Backend : {display_backend(config, getattr(fs, 'backend', 'dynamic'))}")
|
|
101
101
|
logger.info(f"Results saved to {zarr_path}")
|
|
102
102
|
|
|
103
|
+
for name, res in results.items():
|
|
104
|
+
if isinstance(res, dict) and (s3_uri := res.get("metadata", {}).get("s3_uri")):
|
|
105
|
+
logger.info(f" Run outputs (S3): {s3_uri}")
|
|
106
|
+
|
|
103
107
|
if export_images:
|
|
104
108
|
try:
|
|
105
109
|
plot_results(results, fname=f"{base_name}_results.png")
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
"""CLI-side HTTP client for containerized providers (OpenMC, FESTIM, …).
|
|
2
2
|
|
|
3
3
|
A provider that runs in a Docker container does its real work inside the
|
|
4
|
-
container (in ``
|
|
4
|
+
container (in ``processforge.api.serve``). The CLI side must NOT import the
|
|
5
5
|
backend library (OpenMC, FESTIM, …) locally — instead it speaks HTTP to the
|
|
6
6
|
container's ``provider_server.py`` instance. :class:`ContainerProviderClient`
|
|
7
7
|
implements the :class:`~processforge.providers.base.AbstractProvider` contract
|
|
8
8
|
as a thin HTTP wrapper around that server.
|
|
9
9
|
|
|
10
|
-
Request/response contract (matches ``
|
|
10
|
+
Request/response contract (matches ``processforge.api.serve``)
|
|
11
11
|
----------------------------------------------------------------
|
|
12
12
|
* ``POST /run`` with a JSON body
|
|
13
13
|
``{"unit_config", "materials", "inlet", "output_dir", "provider_config"}``.
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
"""S3 upload helper for provider containers.
|
|
2
|
+
|
|
3
|
+
Uploads a provider's run-output directory (``run_dir``) to S3 so ephemeral
|
|
4
|
+
container-local artifacts (``statepoint.h5``, mesh tallies, ``*.h5m``) survive
|
|
5
|
+
after the container stops. The container opts in by setting ``S3_BUCKET`` in its
|
|
6
|
+
environment; credential env vars reuse the convention from
|
|
7
|
+
:func:`processforge.result.save_results_zarr_s3`.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from __future__ import annotations
|
|
11
|
+
|
|
12
|
+
import os
|
|
13
|
+
from datetime import datetime, timezone
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def s3_storage_options() -> dict:
|
|
17
|
+
"""Build s3fs storage options from environment variables.
|
|
18
|
+
|
|
19
|
+
Returns an empty dict when no credentials are configured so s3fs falls
|
|
20
|
+
back to its default credential chain (e.g. instance/role-based auth).
|
|
21
|
+
"""
|
|
22
|
+
opts: dict = {}
|
|
23
|
+
key = os.environ.get("S3_ACCESS_KEY")
|
|
24
|
+
secret = os.environ.get("S3_SECRET_KEY")
|
|
25
|
+
if key:
|
|
26
|
+
opts["key"] = key
|
|
27
|
+
if secret:
|
|
28
|
+
opts["secret"] = secret
|
|
29
|
+
client_kwargs = {
|
|
30
|
+
k: v
|
|
31
|
+
for k, v in {
|
|
32
|
+
"endpoint_url": os.environ.get("S3_ENDPOINT_URL"),
|
|
33
|
+
"region_name": os.environ.get("S3_REGION_NAME", "ams3"),
|
|
34
|
+
}.items()
|
|
35
|
+
if v
|
|
36
|
+
}
|
|
37
|
+
if client_kwargs:
|
|
38
|
+
opts["client_kwargs"] = client_kwargs
|
|
39
|
+
return opts
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def upload_directory_to_s3(run_dir: str) -> str | None:
|
|
43
|
+
"""Upload *run_dir* recursively to S3.
|
|
44
|
+
|
|
45
|
+
Reads the destination from the container environment:
|
|
46
|
+
|
|
47
|
+
* ``S3_BUCKET`` — required; enables the upload. When unset, returns ``None``
|
|
48
|
+
and the caller keeps its local artifacts.
|
|
49
|
+
* ``S3_PREFIX`` — optional key prefix (e.g. ``openmc-runs``).
|
|
50
|
+
|
|
51
|
+
The object key is ``<S3_PREFIX>/<run_dir_basename>-<utc_stamp>/`` so
|
|
52
|
+
repeated runs do not clobber each other.
|
|
53
|
+
|
|
54
|
+
Returns the uploaded ``s3://`` URI, or ``None`` when disabled.
|
|
55
|
+
"""
|
|
56
|
+
bucket = os.environ.get("S3_BUCKET")
|
|
57
|
+
if not bucket:
|
|
58
|
+
return None
|
|
59
|
+
|
|
60
|
+
prefix = os.environ.get("S3_PREFIX", "").strip("/")
|
|
61
|
+
tag = f"{os.path.basename(run_dir.rstrip('/'))}-{datetime.now(timezone.utc):%Y%m%dT%H%M%SZ}"
|
|
62
|
+
s3_dir = f"{prefix + '/' if prefix else ''}{tag}"
|
|
63
|
+
|
|
64
|
+
import s3fs
|
|
65
|
+
|
|
66
|
+
s3fs.S3FileSystem(**s3_storage_options()).put(
|
|
67
|
+
run_dir, f"s3://{bucket}/{s3_dir}", recursive=True
|
|
68
|
+
)
|
|
69
|
+
return f"s3://{bucket}/{s3_dir}"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: processforge
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.10
|
|
4
4
|
Summary: A Python-based process simulation framework for chemical engineering applications.
|
|
5
5
|
Author-email: Processforge Team <team@processforge.dev>
|
|
6
6
|
License-Expression: BSD-3-Clause
|
|
@@ -33,6 +33,7 @@ Requires-Dist: typer>=0.12
|
|
|
33
33
|
Provides-Extra: api
|
|
34
34
|
Requires-Dist: fastapi>=0.110; extra == "api"
|
|
35
35
|
Requires-Dist: uvicorn>=0.29; extra == "api"
|
|
36
|
+
Requires-Dist: s3fs>=2024.0; extra == "api"
|
|
36
37
|
Provides-Extra: eo
|
|
37
38
|
Requires-Dist: pyomo>=6.7; extra == "eo"
|
|
38
39
|
Provides-Extra: eo-casadi
|
|
@@ -107,6 +107,7 @@ src/processforge/units/valve.py
|
|
|
107
107
|
src/processforge/utils/__init__.py
|
|
108
108
|
src/processforge/utils/flowsheet_diagram.py
|
|
109
109
|
src/processforge/utils/mermaid_diagram.py
|
|
110
|
+
src/processforge/utils/s3_upload.py
|
|
110
111
|
src/processforge/utils/topology.py
|
|
111
112
|
src/processforge/utils/unit_consistency.py
|
|
112
113
|
src/processforge/utils/validate_flowsheet.py
|
|
@@ -115,5 +116,6 @@ tests/test_cli.py
|
|
|
115
116
|
tests/test_festim_provider.py
|
|
116
117
|
tests/test_init.py
|
|
117
118
|
tests/test_providers.py
|
|
119
|
+
tests/test_s3_upload.py
|
|
118
120
|
tests/test_state.py
|
|
119
121
|
tests/test_types.py
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
"""Tests for the S3 run-output upload helper."""
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
import os
|
|
5
|
+
import sys
|
|
6
|
+
from datetime import datetime, timezone
|
|
7
|
+
from unittest.mock import MagicMock, patch
|
|
8
|
+
|
|
9
|
+
import pytest
|
|
10
|
+
|
|
11
|
+
from processforge.utils import s3_upload
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@pytest.fixture
|
|
15
|
+
def clean_env(monkeypatch):
|
|
16
|
+
for var in (
|
|
17
|
+
"S3_BUCKET",
|
|
18
|
+
"S3_PREFIX",
|
|
19
|
+
"S3_ACCESS_KEY",
|
|
20
|
+
"S3_SECRET_KEY",
|
|
21
|
+
"S3_ENDPOINT_URL",
|
|
22
|
+
"S3_REGION_NAME",
|
|
23
|
+
):
|
|
24
|
+
monkeypatch.delenv(var, raising=False)
|
|
25
|
+
return monkeypatch
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def test_s3_storage_options_defaults_to_ams3(clean_env):
|
|
29
|
+
opts = s3_upload.s3_storage_options()
|
|
30
|
+
assert opts["client_kwargs"]["region_name"] == "ams3"
|
|
31
|
+
# No creds configured -> not present, s3fs uses default chain.
|
|
32
|
+
assert "key" not in opts
|
|
33
|
+
assert "secret" not in opts
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def test_s3_storage_options_includes_credentials(clean_env):
|
|
37
|
+
clean_env.setenv("S3_ACCESS_KEY", "ak")
|
|
38
|
+
clean_env.setenv("S3_SECRET_KEY", "sk")
|
|
39
|
+
clean_env.setenv("S3_ENDPOINT_URL", "https://s3.example.com")
|
|
40
|
+
opts = s3_upload.s3_storage_options()
|
|
41
|
+
assert opts["key"] == "ak"
|
|
42
|
+
assert opts["secret"] == "sk"
|
|
43
|
+
assert opts["client_kwargs"]["endpoint_url"] == "https://s3.example.com"
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def test_upload_directory_to_s3_disabled_without_bucket(clean_env):
|
|
47
|
+
assert s3_upload.upload_directory_to_s3("/tmp/run") is None
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def test_upload_directory_to_s3_uploads_recursively(clean_env):
|
|
51
|
+
clean_env.setenv("S3_BUCKET", "my-bucket")
|
|
52
|
+
clean_env.setenv("S3_PREFIX", "openmc-runs")
|
|
53
|
+
|
|
54
|
+
mock_fs = MagicMock()
|
|
55
|
+
mock_s3fs = MagicMock()
|
|
56
|
+
mock_s3fs.S3FileSystem.return_value = mock_fs
|
|
57
|
+
|
|
58
|
+
with patch.dict(sys.modules, {"s3fs": mock_s3fs}):
|
|
59
|
+
uri = s3_upload.upload_directory_to_s3("/tmp/processforge/openmc/msre_run")
|
|
60
|
+
|
|
61
|
+
assert uri.startswith("s3://my-bucket/openmc-runs/msre_run-")
|
|
62
|
+
assert uri.endswith(datetime.now(timezone.utc).strftime("%Y%m%dT%H%M%SZ")[:8]) or "-" in uri
|
|
63
|
+
mock_fs.put.assert_called_once()
|
|
64
|
+
args, kwargs = mock_fs.put.call_args
|
|
65
|
+
assert args[0] == "/tmp/processforge/openmc/msre_run"
|
|
66
|
+
assert args[1].startswith("s3://my-bucket/openmc-runs/msre_run-")
|
|
67
|
+
assert kwargs.get("recursive") is True
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def test_upload_directory_to_s3_no_prefix(clean_env):
|
|
71
|
+
clean_env.setenv("S3_BUCKET", "b")
|
|
72
|
+
|
|
73
|
+
mock_fs = MagicMock()
|
|
74
|
+
mock_s3fs = MagicMock()
|
|
75
|
+
mock_s3fs.S3FileSystem.return_value = mock_fs
|
|
76
|
+
|
|
77
|
+
with patch.dict(sys.modules, {"s3fs": mock_s3fs}):
|
|
78
|
+
uri = s3_upload.upload_directory_to_s3("/data/festim")
|
|
79
|
+
|
|
80
|
+
assert uri == f"s3://b/festim-{datetime.now(timezone.utc):%Y%m%dT%H%M%SZ}"
|
|
81
|
+
assert mock_fs.put.call_args[1].get("recursive") is True
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{processforge-0.3.9 → processforge-0.3.10}/src/processforge/providers/base_jacobian_mixin.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{processforge-0.3.9 → processforge-0.3.10}/src/processforge/providers/jacobian_contributor.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{processforge-0.3.9 → processforge-0.3.10}/src/processforge/providers/reference_state_registry.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|