tlpytools 0.2.3__tar.gz → 0.2.5__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.
Files changed (60) hide show
  1. {tlpytools-0.2.3 → tlpytools-0.2.5}/.env.example +3 -2
  2. {tlpytools-0.2.3 → tlpytools-0.2.5}/.github/copilot-instructions.md +2 -2
  3. {tlpytools-0.2.3 → tlpytools-0.2.5}/.github/workflows/deploy.yml +1 -1
  4. {tlpytools-0.2.3 → tlpytools-0.2.5}/CHANGELOG.md +28 -0
  5. {tlpytools-0.2.3 → tlpytools-0.2.5}/DEVELOPER_GUIDE.md +2 -7
  6. {tlpytools-0.2.3 → tlpytools-0.2.5}/PKG-INFO +2 -1
  7. {tlpytools-0.2.3 → tlpytools-0.2.5}/pyproject.toml +2 -1
  8. {tlpytools-0.2.3 → tlpytools-0.2.5}/src/tlpytools/__init__.py +1 -1
  9. {tlpytools-0.2.3 → tlpytools-0.2.5}/src/tlpytools/orca/orchestrator.py +72 -168
  10. {tlpytools-0.2.3 → tlpytools-0.2.5}/tests/test_orca_unit.py +40 -6
  11. {tlpytools-0.2.3 → tlpytools-0.2.5}/uv.lock +106 -59
  12. {tlpytools-0.2.3 → tlpytools-0.2.5}/.github/skills/README.md +0 -0
  13. {tlpytools-0.2.3 → tlpytools-0.2.5}/.github/skills/prepare-official-release/SKILL.md +0 -0
  14. {tlpytools-0.2.3 → tlpytools-0.2.5}/.github/workflows/code-formatting-pr.yml +0 -0
  15. {tlpytools-0.2.3 → tlpytools-0.2.5}/.github/workflows/code-formatting.yml +0 -0
  16. {tlpytools-0.2.3 → tlpytools-0.2.5}/.github/workflows/test.yml +0 -0
  17. {tlpytools-0.2.3 → tlpytools-0.2.5}/.gitignore +0 -0
  18. {tlpytools-0.2.3 → tlpytools-0.2.5}/.pre-commit-config.yaml +0 -0
  19. {tlpytools-0.2.3 → tlpytools-0.2.5}/.python-version +0 -0
  20. {tlpytools-0.2.3 → tlpytools-0.2.5}/ENVIRONMENT_VARIABLES.md +0 -0
  21. {tlpytools-0.2.3 → tlpytools-0.2.5}/Makefile +0 -0
  22. {tlpytools-0.2.3 → tlpytools-0.2.5}/README.md +0 -0
  23. {tlpytools-0.2.3 → tlpytools-0.2.5}/docs/adls_server.md +0 -0
  24. {tlpytools-0.2.3 → tlpytools-0.2.5}/docs/azure_credential_manager.md +0 -0
  25. {tlpytools-0.2.3 → tlpytools-0.2.5}/docs/diagrams/README.md +0 -0
  26. {tlpytools-0.2.3 → tlpytools-0.2.5}/docs/diagrams/orca_cloud_workflow.drawio +0 -0
  27. {tlpytools-0.2.3 → tlpytools-0.2.5}/docs/diagrams/orca_detailed_steps.drawio +0 -0
  28. {tlpytools-0.2.3 → tlpytools-0.2.5}/docs/diagrams/orca_file_structure.drawio +0 -0
  29. {tlpytools-0.2.3 → tlpytools-0.2.5}/docs/diagrams/orca_local_workflow.drawio +0 -0
  30. {tlpytools-0.2.3 → tlpytools-0.2.5}/docs/diagrams/orca_main_features.drawio +0 -0
  31. {tlpytools-0.2.3 → tlpytools-0.2.5}/docs/unified_logging.md +0 -0
  32. {tlpytools-0.2.3 → tlpytools-0.2.5}/requirements.txt +0 -0
  33. {tlpytools-0.2.3 → tlpytools-0.2.5}/src/examples/batchtask.py +0 -0
  34. {tlpytools-0.2.3 → tlpytools-0.2.5}/src/examples/data_files/example.csv +0 -0
  35. {tlpytools-0.2.3 → tlpytools-0.2.5}/src/examples/mydataproject.py +0 -0
  36. {tlpytools-0.2.3 → tlpytools-0.2.5}/src/examples/readwritedata.py +0 -0
  37. {tlpytools-0.2.3 → tlpytools-0.2.5}/src/examples/unified_logging.py +0 -0
  38. {tlpytools-0.2.3 → tlpytools-0.2.5}/src/tlpytools/adls_server.py +0 -0
  39. {tlpytools-0.2.3 → tlpytools-0.2.5}/src/tlpytools/azure_credential.py +0 -0
  40. {tlpytools-0.2.3 → tlpytools-0.2.5}/src/tlpytools/config.py +0 -0
  41. {tlpytools-0.2.3 → tlpytools-0.2.5}/src/tlpytools/data.py +0 -0
  42. {tlpytools-0.2.3 → tlpytools-0.2.5}/src/tlpytools/data_store.py +0 -0
  43. {tlpytools-0.2.3 → tlpytools-0.2.5}/src/tlpytools/env_config.py +0 -0
  44. {tlpytools-0.2.3 → tlpytools-0.2.5}/src/tlpytools/log.py +0 -0
  45. {tlpytools-0.2.3 → tlpytools-0.2.5}/src/tlpytools/orca/README.md +0 -0
  46. {tlpytools-0.2.3 → tlpytools-0.2.5}/src/tlpytools/orca/__init__.py +0 -0
  47. {tlpytools-0.2.3 → tlpytools-0.2.5}/src/tlpytools/orca/__main__.py +0 -0
  48. {tlpytools-0.2.3 → tlpytools-0.2.5}/src/tlpytools/orca/batch_task_runner.py +0 -0
  49. {tlpytools-0.2.3 → tlpytools-0.2.5}/src/tlpytools/orca/cli.py +0 -0
  50. {tlpytools-0.2.3 → tlpytools-0.2.5}/src/tlpytools/orca/orca_model_config_barebone.yaml +0 -0
  51. {tlpytools-0.2.3 → tlpytools-0.2.5}/src/tlpytools/orca/orca_model_config_example.yaml +0 -0
  52. {tlpytools-0.2.3 → tlpytools-0.2.5}/src/tlpytools/sql_server.py +0 -0
  53. {tlpytools-0.2.3 → tlpytools-0.2.5}/tests/README.md +0 -0
  54. {tlpytools-0.2.3 → tlpytools-0.2.5}/tests/__init__.py +0 -0
  55. {tlpytools-0.2.3 → tlpytools-0.2.5}/tests/conftest.py +0 -0
  56. {tlpytools-0.2.3 → tlpytools-0.2.5}/tests/run_tests.py +0 -0
  57. {tlpytools-0.2.3 → tlpytools-0.2.5}/tests/test_azure_credential.py +0 -0
  58. {tlpytools-0.2.3 → tlpytools-0.2.5}/tests/test_basic.py +0 -0
  59. {tlpytools-0.2.3 → tlpytools-0.2.5}/tests/test_core.py +0 -0
  60. {tlpytools-0.2.3 → tlpytools-0.2.5}/tests/test_orca_integration.py +0 -0
@@ -7,15 +7,16 @@
7
7
  # Copy this file to .env and modify the values as needed
8
8
 
9
9
  # Required Environment Variables for Azure Batch
10
- BATCH_ACCOUNT_ENDPOINT=https://your-batch-account.your-region.batch.azure.com
10
+ BATCH_ACCOUNT_ENDPOINT=your-batch-account.your-region.batch.azure.com
11
11
  BATCH_API_VERSION=2024-07-01.20.0
12
12
  IMAGE_REGISTRY_ENDPOINT=your-registry.azurecr.io
13
13
  AZURE_SUBSCRIPTION_ID=your-subscription-id
14
14
  AZURE_RESOURCE_GROUP=your-resource-group
15
15
  MANAGED_IDENTITY_NAME=your-managed-identity
16
16
 
17
- # Azure Data Lake Storage URL
17
+ # Azure Data Lake Storage
18
18
  ORCA_ADLS_URL=yourstorageaccount.dfs.core.windows.net
19
+ ORCA_ADLS_CONTAINER=yourcontainer
19
20
 
20
21
  # Azure SQL Server URI
21
22
  TLPT_AZURE_SQL_URI=yoursever.database.windows.net
@@ -98,8 +98,8 @@ Interpretation for agent PRs:
98
98
 
99
99
  Observed result:
100
100
  - Build succeeds and produces:
101
- - `dist/tlpytools-0.2.3.tar.gz`
102
- - `dist/tlpytools-0.2.3-py3-none-any.whl`
101
+ - `dist/tlpytools-0.2.5.tar.gz`
102
+ - `dist/tlpytools-0.2.5-py3-none-any.whl`
103
103
 
104
104
  ### 5) Run
105
105
  - ORCA CLI (module form):
@@ -4,7 +4,7 @@ on:
4
4
  workflow_dispatch:
5
5
  inputs:
6
6
  version:
7
- description: 'Version number to release (e.g., 0.2.3)'
7
+ description: 'Version number to release (e.g., 0.2.5)'
8
8
  required: true
9
9
  type: string
10
10
  prerelease:
@@ -2,6 +2,34 @@
2
2
 
3
3
  All notable changes to TLPyTools will be documented in this file.
4
4
 
5
+ ## [0.2.5]
6
+
7
+ ### Changed
8
+ - **Dependency update:**
9
+ - Add matplotlib as a dependency with version specifications for compatibility
10
+ - **ADLS configuration moved to environment variables:**
11
+ - `adls_url` and `adls_container` are no longer read from `operational_mode.cloud` in YAML config
12
+ - Both are now read exclusively from `ORCA_ADLS_URL` and `ORCA_ADLS_CONTAINER` environment variables; an error is raised at runtime if either is missing
13
+ - `adls_folder` is now derived solely from the `project_folder` parameter passed to `OrcaOrchestrator`; the `operational_mode.cloud` YAML subsection has been removed from the default config template
14
+ - **Error dump restricted to cloud production mode:**
15
+ - Error dumps are now only created when `operational_mode.type` is `cloud_production`; they are silently skipped in `local_testing` mode regardless of the `create_error_dump` config setting
16
+ - **Error dump operations log removed:**
17
+ - `create_error_dump` no longer writes a CSV operations log file; a single `logger.info` message reports the dump path instead
18
+ - The `export_log` parameter has been removed from `create_error_dump`
19
+ - **Improved model run completion reporting in `print_execution_summary`:**
20
+ - `[ERROR] MODEL RUN FAILED` — run ended with an error
21
+ - `[OK] MODEL RUN COMPLETED` — all iterations and steps completed successfully
22
+ - `[OK] MODEL RUN IS PARTIALLY COMPLETED WITH NO ERRORS` — run stopped cleanly before all iterations were done (e.g. after `run_one_step` or `run_one_iteration`)
23
+
24
+ ### Fixed
25
+ - **Unit test for ADLS config now validates `.env.example`:**
26
+ - `test_get_adls_config` parses `.env.example` at test time and asserts that `ORCA_ADLS_URL` and `ORCA_ADLS_CONTAINER` are present; the test fails if either variable is removed from the example file
27
+
28
+ ## [0.2.4]
29
+
30
+ ### Changed
31
+ * Optimize archive creation by copying single zip files directly and enhancing logging
32
+
5
33
  ## [0.2.3]
6
34
 
7
35
  ### Fixed
@@ -200,7 +200,7 @@ make check-all
200
200
  4. Click **"Run workflow"** button
201
201
  5. Fill in the required information:
202
202
  - **Branch**: Select `main` (or your release branch)
203
- - **Version number**: Enter the new version (e.g., `0.2.3`)
203
+ - **Version number**: Enter the new version (e.g., `0.2.5`)
204
204
  - **Is this a pre-release?**: Check if this is a pre-release version
205
205
 
206
206
  #### 3. Monitor the Release
@@ -219,7 +219,7 @@ After the workflow completes:
219
219
 
220
220
  ```bash
221
221
  # Verify the package is available on PyPI
222
- pip install tlpytools==0.2.3 # Replace with your version
222
+ pip install tlpytools==0.2.5 # Replace with your version
223
223
 
224
224
  # Test installation in a fresh environment
225
225
  python -c "import tlpytools; print(tlpytools.__version__)"
@@ -233,11 +233,6 @@ TLPyTools follows semantic versioning (SemVer):
233
233
  - **Minor** (0.x.0): New features, backwards compatible
234
234
  - **Patch** (0.0.x): Bug fixes, backwards compatible
235
235
 
236
- Examples:
237
- - `0.1.7` → `0.1.8` (patch release)
238
- - `0.1.8` → `0.2.3` (minor release)
239
- - `0.2.3` → `1.0.0` (major release)
240
-
241
236
  ### Pre-releases
242
237
 
243
238
  For testing purposes, you can create pre-release versions:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: tlpytools
3
- Version: 0.2.3
3
+ Version: 0.2.5
4
4
  Summary: TransLink's Python Tools - A comprehensive toolkit for transportation modeling and forecasting
5
5
  Project-URL: Homepage, https://github.com/TransLinkForecasting/tlpytools
6
6
  Project-URL: Bug Tracker, https://github.com/TransLinkForecasting/tlpytools/issues
@@ -23,6 +23,7 @@ Requires-Dist: coverage>=7.10.6
23
23
  Requires-Dist: cryptography>=3.4.7
24
24
  Requires-Dist: cryptpandas>=0.1.1
25
25
  Requires-Dist: ipykernel>=7.2.0
26
+ Requires-Dist: matplotlib>=3.10.9
26
27
  Requires-Dist: notebook>=7.5.6
27
28
  Requires-Dist: numpy>=1.18
28
29
  Requires-Dist: openmatrix>=0.3
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "tlpytools"
7
- version = "0.2.3"
7
+ version = "0.2.5"
8
8
  description = "TransLink's Python Tools - A comprehensive toolkit for transportation modeling and forecasting"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.10.0, <3.13"
@@ -26,6 +26,7 @@ classifiers = [
26
26
  # Runtime dependencies: these are installed when a user `pip install tlpytools`
27
27
  # and also when a developer runs `pip install -e .`
28
28
  dependencies = [
29
+ "matplotlib>=3.10.9",
29
30
  "pandas>=1.1",
30
31
  "numpy>=1.18",
31
32
  "sqlalchemy>=1.4",
@@ -2,7 +2,7 @@
2
2
  TLPyTools - A set of tools for building models at the TransLink Forecasting Team
3
3
  """
4
4
 
5
- __version__ = "0.2.3"
5
+ __version__ = "0.2.5"
6
6
 
7
7
  # Core modules that should always be available (minimal dependencies)
8
8
  from . import log
@@ -2144,7 +2144,6 @@ class OrcaScenario:
2144
2144
  iteration: int,
2145
2145
  error_message: str,
2146
2146
  include_all_scenario: bool = False,
2147
- export_log: bool = True,
2148
2147
  ) -> bool:
2149
2148
  """
2150
2149
  Create an error dump when a model execution fails.
@@ -2161,7 +2160,6 @@ class OrcaScenario:
2161
2160
  iteration: Current iteration number
2162
2161
  error_message: Error message describing the failure
2163
2162
  include_all_scenario: If True, includes entire scenario in error dump
2164
- export_log: Whether to export operation log
2165
2163
 
2166
2164
  Returns:
2167
2165
  bool: True if error dump was created successfully, False otherwise
@@ -2188,8 +2186,6 @@ class OrcaScenario:
2188
2186
  "dump_contents": [],
2189
2187
  }
2190
2188
 
2191
- operations = []
2192
-
2193
2189
  # 1. Copy the failed step directory if it exists
2194
2190
  step_dir = os.path.join(self.scenario_path, step_name)
2195
2191
  if os.path.exists(step_dir):
@@ -2205,26 +2201,6 @@ class OrcaScenario:
2205
2201
 
2206
2202
  if success:
2207
2203
  error_info["dump_contents"].append(f"{step_name}/")
2208
- operations.append(
2209
- {
2210
- "source": step_dir,
2211
- "target": step_dump_dir,
2212
- "type": "directory_copy",
2213
- "status": "success",
2214
- "timestamp": time.strftime("%Y-%m-%d %H:%M:%S"),
2215
- }
2216
- )
2217
- else:
2218
- operations.append(
2219
- {
2220
- "source": step_dir,
2221
- "target": step_dump_dir,
2222
- "type": "directory_copy",
2223
- "status": "failed",
2224
- "timestamp": time.strftime("%Y-%m-%d %H:%M:%S"),
2225
- "error": "Failed to copy step directory",
2226
- }
2227
- )
2228
2204
 
2229
2205
  # 2. Copy configuration files
2230
2206
  config_files = [
@@ -2243,25 +2219,11 @@ class OrcaScenario:
2243
2219
  try:
2244
2220
  shutil.copy2(config_path, target_path)
2245
2221
  error_info["dump_contents"].append(f"config/{config_file}")
2246
- operations.append(
2247
- {
2248
- "source": config_path,
2249
- "target": target_path,
2250
- "type": "file_copy",
2251
- "status": "success",
2252
- "timestamp": time.strftime("%Y-%m-%d %H:%M:%S"),
2253
- }
2254
- )
2255
2222
  except Exception as e:
2256
- operations.append(
2257
- {
2258
- "source": config_path,
2259
- "target": target_path,
2260
- "type": "file_copy",
2261
- "status": "failed",
2262
- "timestamp": time.strftime("%Y-%m-%d %H:%M:%S"),
2263
- "error": str(e),
2264
- }
2223
+ self.logger.warning(
2224
+ "Failed to copy config file %s to error dump: %s",
2225
+ config_file,
2226
+ e,
2265
2227
  )
2266
2228
 
2267
2229
  # 3. Copy log files
@@ -2276,25 +2238,9 @@ class OrcaScenario:
2276
2238
  try:
2277
2239
  shutil.copy2(log_file, target_path)
2278
2240
  error_info["dump_contents"].append(f"{LOGS_DIR}/{log_name}")
2279
- operations.append(
2280
- {
2281
- "source": log_file,
2282
- "target": target_path,
2283
- "type": "file_copy",
2284
- "status": "success",
2285
- "timestamp": time.strftime("%Y-%m-%d %H:%M:%S"),
2286
- }
2287
- )
2288
2241
  except Exception as e:
2289
- operations.append(
2290
- {
2291
- "source": log_file,
2292
- "target": target_path,
2293
- "type": "file_copy",
2294
- "status": "failed",
2295
- "timestamp": time.strftime("%Y-%m-%d %H:%M:%S"),
2296
- "error": str(e),
2297
- }
2242
+ self.logger.warning(
2243
+ "Failed to copy log file %s to error dump: %s", log_name, e
2298
2244
  )
2299
2245
 
2300
2246
  # 4. Copy outputs directory if it exists
@@ -2312,26 +2258,6 @@ class OrcaScenario:
2312
2258
 
2313
2259
  if success:
2314
2260
  error_info["dump_contents"].append(f"{OUTPUTS_DIR}/")
2315
- operations.append(
2316
- {
2317
- "source": outputs_dir,
2318
- "target": outputs_dump_dir,
2319
- "type": "directory_copy",
2320
- "status": "success",
2321
- "timestamp": time.strftime("%Y-%m-%d %H:%M:%S"),
2322
- }
2323
- )
2324
- else:
2325
- operations.append(
2326
- {
2327
- "source": outputs_dir,
2328
- "target": outputs_dump_dir,
2329
- "type": "directory_copy",
2330
- "status": "failed",
2331
- "timestamp": time.strftime("%Y-%m-%d %H:%M:%S"),
2332
- "error": "Failed to copy outputs directory",
2333
- }
2334
- )
2335
2261
 
2336
2262
  # 5. Optionally copy entire scenario (excluding the error dump itself)
2337
2263
  if include_all_scenario:
@@ -2348,26 +2274,6 @@ class OrcaScenario:
2348
2274
 
2349
2275
  if success:
2350
2276
  error_info["dump_contents"].append("full_scenario/")
2351
- operations.append(
2352
- {
2353
- "source": self.scenario_path,
2354
- "target": full_dump_dir,
2355
- "type": "full_scenario_copy",
2356
- "status": "success",
2357
- "timestamp": time.strftime("%Y-%m-%d %H:%M:%S"),
2358
- }
2359
- )
2360
- else:
2361
- operations.append(
2362
- {
2363
- "source": self.scenario_path,
2364
- "target": full_dump_dir,
2365
- "type": "full_scenario_copy",
2366
- "status": "failed",
2367
- "timestamp": time.strftime("%Y-%m-%d %H:%M:%S"),
2368
- "error": "Failed to copy full scenario",
2369
- }
2370
- )
2371
2277
 
2372
2278
  # 6. Save error information
2373
2279
  error_info_file = os.path.join(error_dump_dir, "error_info.json")
@@ -2395,23 +2301,8 @@ class OrcaScenario:
2395
2301
  error_dump_dir,
2396
2302
  )
2397
2303
 
2398
- # 8. Log all operations
2399
- if export_log and operations:
2400
- self.log_file_operations(
2401
- operations=operations,
2402
- log_dir=error_dump_base,
2403
- operation_type="error_dump",
2404
- export_log=export_log,
2405
- )
2406
-
2407
- # Summary logging
2408
- self.logger.info("Error dump completed successfully")
2409
- self.logger.debug(
2410
- "Error dump location: %s", zip_path if zip_success else error_dump_dir
2411
- )
2412
- self.logger.debug(
2413
- "Error dump contents: %s", ", ".join(error_info["dump_contents"])
2414
- )
2304
+ dump_location = zip_path if zip_success else error_dump_dir
2305
+ self.logger.info("Error dump created at: %s", dump_location)
2415
2306
 
2416
2307
  return True
2417
2308
 
@@ -2764,30 +2655,13 @@ class OrcaOrchestrator:
2764
2655
  raise ValueError(f"Invalid mode: {self.mode}")
2765
2656
 
2766
2657
  # Initialize state - for cloud mode, this will load the cloud-synchronized state
2767
- # Get project name from config or project_folder_override
2768
- # Priority: adls_folder in YAML > project_folder parameter > default
2769
- adls_folder_in_config = (
2770
- self.config.get("operational_mode", {}).get("cloud", {}).get("adls_folder")
2771
- )
2772
-
2773
- if adls_folder_in_config:
2774
- # Use adls_folder from YAML if already set
2775
- project_name = adls_folder_in_config
2776
- self.logger.debug("Using adls_folder from config: '%s'", project_name)
2777
- elif self.project_folder_override:
2778
- # Use project_folder parameter if provided and adls_folder not in YAML
2658
+ # project_folder parameter is the authoritative source for project name
2659
+ if self.project_folder_override:
2779
2660
  project_name = self.project_folder_override
2780
- # Automatically inject into config for consistency
2781
- if "operational_mode" not in self.config:
2782
- self.config["operational_mode"] = {}
2783
- if "cloud" not in self.config["operational_mode"]:
2784
- self.config["operational_mode"]["cloud"] = {}
2785
- self.config["operational_mode"]["cloud"]["adls_folder"] = project_name
2786
2661
  self.logger.debug(
2787
- "Set adls_folder from project_folder parameter: '%s'", project_name
2662
+ "Using project folder as project name: '%s'", project_name
2788
2663
  )
2789
2664
  else:
2790
- # Use default if neither is set
2791
2665
  project_name = "proj_unnamed"
2792
2666
  self.logger.debug("Using default project name: '%s'", project_name)
2793
2667
 
@@ -3926,10 +3800,10 @@ class OrcaOrchestrator:
3926
3800
  error_config = self.config.get("error_handling", {})
3927
3801
  create_dump = error_config.get("create_error_dump", True)
3928
3802
  include_full_scenario = error_config.get(
3929
- "include_all_files_in_dump", False
3803
+ "include_all_files_in_dump", True
3930
3804
  )
3931
3805
 
3932
- if create_dump:
3806
+ if create_dump and self.mode == "cloud_production":
3933
3807
  # Create error dump when command fails
3934
3808
  self.logger.info(
3935
3809
  "Creating error dump for failed step: %s", step_name
@@ -3939,7 +3813,6 @@ class OrcaOrchestrator:
3939
3813
  iteration=display_iteration,
3940
3814
  error_message=error_msg,
3941
3815
  include_all_scenario=include_full_scenario,
3942
- export_log=True,
3943
3816
  )
3944
3817
 
3945
3818
  if dump_success:
@@ -4062,18 +3935,46 @@ class OrcaOrchestrator:
4062
3935
  "Failed to delete existing archive %s: %s", zip_filename, e
4063
3936
  )
4064
3937
 
4065
- # Use the zip_directory utility function to create the archive
4066
- # Note: zip_directory now logs its own summary
4067
- self.scenario.zip_directory(
4068
- dir_path=step_dir,
4069
- zip_path=archive_path,
4070
- # Skip everything except the specified patterns
4071
- skip_patterns=["*"] + [f"!{pattern}" for pattern in patterns],
4072
- include_empty_dirs=False,
4073
- compression_type=compression_type,
4074
- compresslevel=compresslevel,
3938
+ # Optimisation: if patterns is a single zip file with no wildcards,
3939
+ # copy and rename it directly instead of wrapping it in another zip.
3940
+ single_zip_pattern = (
3941
+ len(patterns) == 1
3942
+ and patterns[0].endswith(".zip")
3943
+ and "*" not in patterns[0]
3944
+ and "?" not in patterns[0]
4075
3945
  )
4076
3946
 
3947
+ if single_zip_pattern:
3948
+ source_zip = os.path.join(step_dir, patterns[0])
3949
+ if os.path.exists(source_zip):
3950
+ os.makedirs(os.path.dirname(archive_path), exist_ok=True)
3951
+ shutil.copy2(source_zip, archive_path)
3952
+ self.logger.info(
3953
+ "Copied single zip file %s -> %s",
3954
+ os.path.basename(source_zip),
3955
+ zip_filename,
3956
+ )
3957
+ else:
3958
+ self.logger.warning(
3959
+ "Single zip pattern '%s' not found at %s, skipping archive: %s",
3960
+ patterns[0],
3961
+ source_zip,
3962
+ archive_name,
3963
+ )
3964
+ continue
3965
+ else:
3966
+ # Use the zip_directory utility function to create the archive
3967
+ # Note: zip_directory now logs its own summary
3968
+ self.scenario.zip_directory(
3969
+ dir_path=step_dir,
3970
+ zip_path=archive_path,
3971
+ # Skip everything except the specified patterns
3972
+ skip_patterns=["*"] + [f"!{pattern}" for pattern in patterns],
3973
+ include_empty_dirs=False,
3974
+ compression_type=compression_type,
3975
+ compresslevel=compresslevel,
3976
+ )
3977
+
4077
3978
  # Register the archive in state for future retrieval
4078
3979
  self._register_output_archive(
4079
3980
  step_name, archive_name, zip_filename, display_iteration
@@ -4262,26 +4163,19 @@ class OrcaOrchestrator:
4262
4163
 
4263
4164
  def _get_adls_config(self):
4264
4165
  """
4265
- Get ADLS configuration from config file.
4166
+ Get ADLS configuration from environment variables and the project_folder parameter.
4266
4167
 
4267
4168
  Returns:
4268
4169
  tuple: (adls_url, adls_container, adls_folder)
4269
4170
  """
4270
- cloud_config = self.config["operational_mode"].get("cloud", {})
4271
-
4272
- adls_url = cloud_config.get("adls_url")
4273
- if adls_url is None:
4274
- adls_base = get_env_var("ORCA_ADLS_URL", required=True)
4275
- adls_url = f"https://{adls_base}"
4171
+ adls_base = get_env_var("ORCA_ADLS_URL", required=True)
4172
+ adls_url = f"https://{adls_base}"
4276
4173
 
4277
- adls_container = cloud_config.get("adls_container", "raw")
4174
+ adls_container = get_env_var("ORCA_ADLS_CONTAINER", required=True)
4278
4175
 
4279
- # Use project_folder override if provided, otherwise use config value
4176
+ adls_folder = self.project_folder_override or "proj_unnamed"
4280
4177
  if self.project_folder_override:
4281
- adls_folder = self.project_folder_override
4282
4178
  self.logger.info("Using project folder override: %s", adls_folder)
4283
- else:
4284
- adls_folder = cloud_config.get("adls_folder", "proj_unnamed")
4285
4179
 
4286
4180
  return adls_url, adls_container, adls_folder
4287
4181
 
@@ -7002,8 +6896,18 @@ class OrcaOrchestrator:
7002
6896
  """
7003
6897
  Print a summary of the model execution results.
7004
6898
  """
6899
+ status = self.state.get("status") if self.state else None
6900
+ all_complete = self.state.is_all_iterations_complete() if self.state else False
6901
+
6902
+ if status == "error":
6903
+ header = "[ERROR] MODEL RUN FAILED"
6904
+ elif all_complete:
6905
+ header = "[OK] MODEL RUN COMPLETED"
6906
+ else:
6907
+ header = "[OK] MODEL RUN IS PARTIALLY COMPLETED WITH NO ERRORS"
6908
+
7005
6909
  print("\n" + "=" * 70)
7006
- print("[OK] MODEL EXECUTION COMPLETED")
6910
+ print(header)
7007
6911
  print("=" * 70)
7008
6912
 
7009
6913
  if self.state:
@@ -7883,6 +7787,7 @@ class OrcaUtil:
7883
7787
  # Required environment variables for cloud operations
7884
7788
  required_env_vars = [
7885
7789
  "ORCA_ADLS_URL",
7790
+ "ORCA_ADLS_CONTAINER",
7886
7791
  "BATCH_ACCOUNT_ENDPOINT",
7887
7792
  "IMAGE_REGISTRY_ENDPOINT",
7888
7793
  "AZURE_SUBSCRIPTION_ID",
@@ -7937,11 +7842,10 @@ class OrcaUtil:
7937
7842
  if tenant_name_output:
7938
7843
  print(f"[INFO] tenantDisplayName: {tenant_name_output}")
7939
7844
 
7940
- # Get cloud configuration from orchestrator
7941
- cloud_config = orchestrator.config.get("operational_mode", {}).get("cloud", {})
7942
- adls_url = cloud_config.get("adls_url", "")
7943
- adls_container = cloud_config.get("adls_container", "")
7944
- adls_folder = cloud_config.get("adls_folder", "")
7845
+ # Get cloud configuration from environment variables
7846
+ adls_url = os.getenv("ORCA_ADLS_URL", "")
7847
+ adls_container = os.getenv("ORCA_ADLS_CONTAINER", "")
7848
+ adls_folder = orchestrator.project_folder_override or ""
7945
7849
 
7946
7850
  # Print detailed configuration status
7947
7851
  print("\n" + "=" * 70)
@@ -530,14 +530,48 @@ class TestOrcaOrchestrator(unittest.TestCase):
530
530
  self.assertEqual(len(archive_files), 0)
531
531
 
532
532
  def test_get_adls_config(self):
533
- """Test ADLS config retrieval."""
534
- orchestrator = self._create_test_orchestrator()
533
+ """Test ADLS config retrieval.
534
+
535
+ Loads .env.example to verify it contains the required variables, then
536
+ uses those values to exercise _get_adls_config so the test breaks if
537
+ either the code or the example file drops a required variable.
538
+ """
539
+ env_example_path = os.path.join(
540
+ os.path.dirname(os.path.dirname(os.path.abspath(__file__))),
541
+ ".env.example",
542
+ )
543
+ self.assertTrue(
544
+ os.path.exists(env_example_path),
545
+ f".env.example not found at {env_example_path}",
546
+ )
547
+
548
+ # Parse .env.example into a dict (skip comments and blank lines)
549
+ env_vars = {}
550
+ with open(env_example_path) as f:
551
+ for line in f:
552
+ line = line.strip()
553
+ if line and not line.startswith("#") and "=" in line:
554
+ key, _, value = line.partition("=")
555
+ env_vars[key.strip()] = value.strip()
556
+
557
+ self.assertIn(
558
+ "ORCA_ADLS_URL", env_vars, "ORCA_ADLS_URL missing from .env.example"
559
+ )
560
+ self.assertIn(
561
+ "ORCA_ADLS_CONTAINER",
562
+ env_vars,
563
+ "ORCA_ADLS_CONTAINER missing from .env.example",
564
+ )
565
+
566
+ with patch.dict(os.environ, env_vars):
567
+ orchestrator = self._create_test_orchestrator()
568
+ orchestrator.project_folder_override = "test_folder"
535
569
 
536
- adls_url, adls_container, adls_folder = orchestrator.get_adls_config()
570
+ adls_url, adls_container, adls_folder = orchestrator.get_adls_config()
537
571
 
538
- self.assertEqual(adls_url, "https://test.dfs.core.windows.net")
539
- self.assertEqual(adls_container, "test")
540
- self.assertEqual(adls_folder, "test_folder")
572
+ self.assertEqual(adls_url, f"https://{env_vars['ORCA_ADLS_URL']}")
573
+ self.assertEqual(adls_container, env_vars["ORCA_ADLS_CONTAINER"])
574
+ self.assertEqual(adls_folder, "test_folder")
541
575
 
542
576
  def test_input_data_initialization(self):
543
577
  """Test that input_data configuration is properly loaded."""
@@ -337,7 +337,7 @@ resolution-markers = [
337
337
  dependencies = [
338
338
  { name = "msgpack", marker = "python_full_version < '3.11'" },
339
339
  { name = "ndindex", marker = "python_full_version < '3.11'" },
340
- { name = "numexpr", marker = "python_full_version < '3.11' and platform_machine != 'wasm32'" },
340
+ { name = "numexpr", version = "2.14.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11' and platform_machine != 'wasm32'" },
341
341
  { name = "numpy", marker = "python_full_version < '3.11'" },
342
342
  { name = "pydantic", marker = "python_full_version < '3.11'" },
343
343
  { name = "requests", marker = "python_full_version < '3.11'" },
@@ -378,7 +378,7 @@ dependencies = [
378
378
  { name = "httpx", extra = ["http2"], marker = "python_full_version >= '3.11'" },
379
379
  { name = "msgpack", marker = "python_full_version >= '3.11'" },
380
380
  { name = "ndindex", marker = "python_full_version >= '3.11'" },
381
- { name = "numexpr", marker = "python_full_version >= '3.11' and platform_machine != 'wasm32'" },
381
+ { name = "numexpr", version = "2.14.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11' and platform_machine != 'wasm32'" },
382
382
  { name = "numpy", marker = "python_full_version >= '3.11'" },
383
383
  { name = "pydantic", marker = "python_full_version >= '3.11'" },
384
384
  { name = "rich", marker = "python_full_version >= '3.11'" },
@@ -446,7 +446,7 @@ version = "0.25.0"
446
446
  source = { registry = "https://pypi.org/simple" }
447
447
  dependencies = [
448
448
  { name = "matplotlib", version = "3.10.9", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" },
449
- { name = "matplotlib", version = "3.11.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" },
449
+ { name = "matplotlib", version = "3.11.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" },
450
450
  { name = "numpy" },
451
451
  { name = "packaging" },
452
452
  { name = "pyproj", version = "3.7.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" },
@@ -674,7 +674,7 @@ dependencies = [
674
674
  { name = "geopy" },
675
675
  { name = "joblib" },
676
676
  { name = "matplotlib", version = "3.10.9", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" },
677
- { name = "matplotlib", version = "3.11.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" },
677
+ { name = "matplotlib", version = "3.11.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" },
678
678
  { name = "mercantile" },
679
679
  { name = "pillow" },
680
680
  { name = "rasterio" },
@@ -1250,11 +1250,11 @@ wheels = [
1250
1250
 
1251
1251
  [[package]]
1252
1252
  name = "filelock"
1253
- version = "3.30.3"
1253
+ version = "3.32.0"
1254
1254
  source = { registry = "https://pypi.org/simple" }
1255
- sdist = { url = "https://files.pythonhosted.org/packages/d6/01/9256cbe36eb2a84501920adad7d0e86738ab0ad60e64f4f5c38d7dd94dc1/filelock-3.30.3.tar.gz", hash = "sha256:6575420cd497ed15fc43a7ac46c48f6b6371c733fc40cf5a4e216871397bc1e2", size = 177706, upload-time = "2026-07-17T15:17:45.342Z" }
1255
+ sdist = { url = "https://files.pythonhosted.org/packages/c0/80/8232b582c4b318b817cf1274ba74976b07b34d35ef439b3eb948f98645a1/filelock-3.32.0.tar.gz", hash = "sha256:7be2ad23a14607ccc71808e68fe30848aeace7058ace17852f68e2a68e310402", size = 213757, upload-time = "2026-07-21T13:17:42.898Z" }
1256
1256
  wheels = [
1257
- { url = "https://files.pythonhosted.org/packages/e7/20/b0d6da41a08b30faef4f20302f5d826a9d39073750cd9100b463eb840cf4/filelock-3.30.3-py3-none-any.whl", hash = "sha256:06e1c6d5e12277022172b7f8d090affe0e8f940f1a37ca45f548855ee51a6b86", size = 94544, upload-time = "2026-07-17T15:17:44.129Z" },
1257
+ { url = "https://files.pythonhosted.org/packages/06/79/b4c714bef36bc4ec2beeae1e0c124f0223888cd8c6feb1cdc56038116920/filelock-3.32.0-py3-none-any.whl", hash = "sha256:d396bea984af47333ef05e50eae7eff88c84256de6112aea0ec48a233c064fe3", size = 97732, upload-time = "2026-07-21T13:17:41.55Z" },
1258
1258
  ]
1259
1259
 
1260
1260
  [[package]]
@@ -1970,7 +1970,7 @@ wheels = [
1970
1970
 
1971
1971
  [[package]]
1972
1972
  name = "jupyterlab"
1973
- version = "4.6.1"
1973
+ version = "4.6.2"
1974
1974
  source = { registry = "https://pypi.org/simple" }
1975
1975
  dependencies = [
1976
1976
  { name = "async-lru" },
@@ -1987,10 +1987,11 @@ dependencies = [
1987
1987
  { name = "tomli", marker = "python_full_version < '3.11'" },
1988
1988
  { name = "tornado" },
1989
1989
  { name = "traitlets" },
1990
+ { name = "typing-extensions", marker = "python_full_version < '3.12'" },
1990
1991
  ]
1991
- sdist = { url = "https://files.pythonhosted.org/packages/bc/2a/d6af53bfd45a43a5bfe7e40ba47ee7a8921a807daf4bb708e3a295bbb54d/jupyterlab-4.6.1.tar.gz", hash = "sha256:75315982ed28427edaa62bb85eadb5105e4043a757643c910efd787fe6ed0837", size = 28179125, upload-time = "2026-06-29T12:48:45.402Z" }
1992
+ sdist = { url = "https://files.pythonhosted.org/packages/7a/7f/51c0c856ab286bdaf5709cf61ed13584ed9d4bee906479707da45b11b353/jupyterlab-4.6.2.tar.gz", hash = "sha256:e18ce8b34f3de350e93cd5b2c4f3ae884cbe266eb76bf5d6825a4ed34c13bcff", size = 28183650, upload-time = "2026-07-21T12:05:24.051Z" }
1992
1993
  wheels = [
1993
- { url = "https://files.pythonhosted.org/packages/5a/81/90ac6cc31d248e83a0d1eab343a5e6e68bc783d3f74fbe61640f42a61da4/jupyterlab-4.6.1-py3-none-any.whl", hash = "sha256:85a58546c831f3dce6cf919468c26874c9065e99c42279fb4abb8e1b552a98bb", size = 17164660, upload-time = "2026-06-29T12:48:41.21Z" },
1994
+ { url = "https://files.pythonhosted.org/packages/63/1f/e39b248c76bb3736bc05a9491a6aa1315414c32dea12f548ecc1b24c758e/jupyterlab-4.6.2-py3-none-any.whl", hash = "sha256:5964447036629adfcd3fc0969effc1da6f47d2cbd0a60b2c2eea7c31be0ec6a8", size = 17166703, upload-time = "2026-07-21T12:05:19.818Z" },
1994
1995
  ]
1995
1996
 
1996
1997
  [[package]]
@@ -2351,7 +2352,7 @@ wheels = [
2351
2352
 
2352
2353
  [[package]]
2353
2354
  name = "matplotlib"
2354
- version = "3.11.0"
2355
+ version = "3.11.1"
2355
2356
  source = { registry = "https://pypi.org/simple" }
2356
2357
  resolution-markers = [
2357
2358
  "python_full_version >= '3.12' and sys_platform == 'win32'",
@@ -2372,25 +2373,25 @@ dependencies = [
2372
2373
  { name = "pyparsing", marker = "python_full_version >= '3.11'" },
2373
2374
  { name = "python-dateutil", marker = "python_full_version >= '3.11'" },
2374
2375
  ]
2375
- sdist = { url = "https://files.pythonhosted.org/packages/1f/24/080c99d223d158d3a8902769269ab6da5b50f7a0e6e072513907e02b7a6c/matplotlib-3.11.0.tar.gz", hash = "sha256:68c0c7be01b30dcca3638934f7f591df73401235cbdbf0d1ab1c71e7db7f8b57", size = 33251176, upload-time = "2026-06-12T02:29:15.508Z" }
2376
+ sdist = { url = "https://files.pythonhosted.org/packages/49/64/f9a391af28f518b11ad45a8a712353c94a0aefce09d3703200e5c54b610a/matplotlib-3.11.1.tar.gz", hash = "sha256:69647db5746941c793d6e445a4cd349323ffb87d9cc958c2ad84a659b4832d30", size = 32612045, upload-time = "2026-07-18T03:39:46.63Z" }
2376
2377
  wheels = [
2377
- { url = "https://files.pythonhosted.org/packages/ce/a2/78f662f1b18968531f67d3fcde1b7ea8496920bacd4f16ddb5b79d112e46/matplotlib-3.11.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:f857524b442f0f36e641868ce2171aafa88cb0bc0644f4e1d8a5df9b32649fef", size = 9436261, upload-time = "2026-06-12T02:27:34.161Z" },
2378
- { url = "https://files.pythonhosted.org/packages/5e/92/044f1de43901310202f4c79acf4f141be53b2ca8d8380e2fcefb3d523a75/matplotlib-3.11.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:57baa92fdc82948ed716eae6d2579d4d6f40965cd8d2f416755b4a72580a3233", size = 9264669, upload-time = "2026-06-12T02:27:37.413Z" },
2379
- { url = "https://files.pythonhosted.org/packages/53/f4/f0b4f9ba7ec14a7af8151f3ad71ecfe3561e6ba38cfab1db3681ba4ca112/matplotlib-3.11.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:630eee0e67d35cce2019a0e670719f4816e3b86aff0fa72729f6c69786fceb45", size = 10021076, upload-time = "2026-06-12T02:27:39.926Z" },
2380
- { url = "https://files.pythonhosted.org/packages/d7/33/4d679c6dcd594a156542080ac907ddccf7b09ca11655c4b28eca8e9ee5da/matplotlib-3.11.0-cp311-cp311-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5106c444d0bf966eee2853548c03772af4ab7199118e086c62fbac8ccb07c055", size = 10828999, upload-time = "2026-06-12T02:27:42.433Z" },
2381
- { url = "https://files.pythonhosted.org/packages/07/74/0a3683802037d8cd013144d77c247219b47f2aabace6fdde74faa12bacf7/matplotlib-3.11.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:4d7aea652b58e686444079be3376ef546bffa1eee9b9bb9c472b9fcf6cf410d3", size = 10913103, upload-time = "2026-06-12T02:27:44.827Z" },
2382
- { url = "https://files.pythonhosted.org/packages/d0/9f/970fcbf381e82ec66fdf5da8ea76e2e9240f61a24011ce9fd1d42c37ac2d/matplotlib-3.11.0-cp311-cp311-win_amd64.whl", hash = "sha256:70a5b3e9a5dab708c0f039709ae7c68d5b4d254e291ef76492cdba230c8bb5e4", size = 9310945, upload-time = "2026-06-12T02:27:46.867Z" },
2383
- { url = "https://files.pythonhosted.org/packages/14/4e/6e7cfed23611265ded53806852343b5c59339e506e84c474a9b5afc3b249/matplotlib-3.11.0-cp311-cp311-win_arm64.whl", hash = "sha256:3d68266213e73823ac3be90615bab0cf31f88851e114cdb1dd25dacf3b01e1a7", size = 8999304, upload-time = "2026-06-12T02:27:48.798Z" },
2384
- { url = "https://files.pythonhosted.org/packages/da/17/f5276b496c61477a6c4fc5e7401f4bfe1c2e5ef7c6cd67896f2ade3809cb/matplotlib-3.11.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:06b5872e9cf11adc8f589ded3ce11bc3e1061ad498259664fabc1f6615beb918", size = 9449976, upload-time = "2026-06-12T02:27:50.989Z" },
2385
- { url = "https://files.pythonhosted.org/packages/82/34/bdd77418adb2178a1d59f044bd67bfebb115896e91b840b8a197eb3f4f4e/matplotlib-3.11.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:0515d495124be3124340e59f164d901ed4484e2246a5b74cfa483cac3b80bd97", size = 9279307, upload-time = "2026-06-12T02:27:53.247Z" },
2386
- { url = "https://files.pythonhosted.org/packages/94/95/7f522393c88313336b20d70fc849555757b2e5febc22b83b3a3f0fd4bce9/matplotlib-3.11.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:be5f93a1d21981bfb802ded0d77a0caa92d4342a47d45754fac77e314a506344", size = 10031353, upload-time = "2026-06-12T02:27:55.215Z" },
2387
- { url = "https://files.pythonhosted.org/packages/87/ce/8f25a0e3186aefd61913e7467d1b999465bcd0d0c03ac695c1b26ca559b7/matplotlib-3.11.0-cp312-cp312-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:41635d7909d19e52e924a521dde6d8f670b0f53ab1d0e8c331fa831554f681d1", size = 10839232, upload-time = "2026-06-12T02:27:57.746Z" },
2388
- { url = "https://files.pythonhosted.org/packages/85/c2/db15da2bbdf9e3ca66df7db8e2c33a1dfed67be24a24d2c878efaaff01d6/matplotlib-3.11.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:94f5000f67ca9faa300863ea17f8bce9175cb67b88bec4bc7780502d53dd7c9e", size = 10923899, upload-time = "2026-06-12T02:28:00.223Z" },
2389
- { url = "https://files.pythonhosted.org/packages/e5/2f/a58a4443a4d052a4ea77557478336aefc26c7981f6408d37adba763aa758/matplotlib-3.11.0-cp312-cp312-win_amd64.whl", hash = "sha256:ac6f1ef39f3d0f9e2463303013094992cdbe0f85f43bc54155bc472b2042768e", size = 9329528, upload-time = "2026-06-12T02:28:02.27Z" },
2390
- { url = "https://files.pythonhosted.org/packages/61/0f/4b669589d47733b97ab9df4b58d6fc1e68acb5ea42a928dc7cbdd6bf5871/matplotlib-3.11.0-cp312-cp312-win_arm64.whl", hash = "sha256:9dd11fb612ce7bc60b1de5b4fc87ff959d22317b5de42aabf392f66f97af22eb", size = 9003413, upload-time = "2026-06-12T02:28:04.49Z" },
2391
- { url = "https://files.pythonhosted.org/packages/0f/c2/f5da6cd37ed6871f5c9b3c0507ddb69f14d6c36fac4541e4e0c60cb8cdfc/matplotlib-3.11.0-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:81ae77077a1e16d37a5b61096ccb07c8d90a99b518fa8256b8f21578932f2f62", size = 9434094, upload-time = "2026-06-12T02:29:09.135Z" },
2392
- { url = "https://files.pythonhosted.org/packages/f8/07/56f66906e0f87a0c6d0d0acbd34dbc9432b1931d8f26ef618bd6f92932a9/matplotlib-3.11.0-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:ddef37840695f5eef65f9f070fe2d2f510f584c2156203f9f622a5b0584efffd", size = 9262183, upload-time = "2026-06-12T02:29:11.283Z" },
2393
- { url = "https://files.pythonhosted.org/packages/0c/d8/c4ecab06b7ea36a570c4f3bd2d48d1799fd5d9174470e45c2194199431e7/matplotlib-3.11.0-pp311-pypy311_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:cf662e5ac5707658cb931e19972c4bd99f7b4f8b7bf79d3c821d239fa6b71e64", size = 10015653, upload-time = "2026-06-12T02:29:13.251Z" },
2378
+ { url = "https://files.pythonhosted.org/packages/6e/d0/791aa183dd88491555cf7d4be0b52b0bcf6c3c2a2c22c815a2e819bf53e2/matplotlib-3.11.1-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:b7cf158e7add54a8d51ac9b5a84abd6d4e13ed4951b4f25f1c5139f41c2addb2", size = 9440302, upload-time = "2026-07-18T03:38:03.844Z" },
2379
+ { url = "https://files.pythonhosted.org/packages/35/74/82bbdf683a301f4478384c8aaba6903631a2ca18294b2d7655c9a542bffb/matplotlib-3.11.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d2ace7273b9a5061a3b420918a16fae1f2dc5dfee1abcc13aba71b5d94b1820c", size = 9268549, upload-time = "2026-07-18T03:38:06.144Z" },
2380
+ { url = "https://files.pythonhosted.org/packages/f0/f0/9b4298911303f74e6d83e64a81d996c0616405ec95046fac7f17e4258b9e/matplotlib-3.11.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:aee55e9041211bf84302ab55ec3965df18dd90ae19f8b58332a7feaf208bfe83", size = 10024922, upload-time = "2026-07-18T03:38:08.236Z" },
2381
+ { url = "https://files.pythonhosted.org/packages/84/6f/0bc3c3d05b021db44c14bc379a7c0df7d57302aa15380c16fd4e63fd6a9b/matplotlib-3.11.1-cp311-cp311-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:96f4bdeea33a8d15a071dbfe6d119451b1d719c733ac666d65357082901a9099", size = 10832170, upload-time = "2026-07-18T03:38:10.276Z" },
2382
+ { url = "https://files.pythonhosted.org/packages/db/4d/e375f39acdb2af5a9342730618608e39790ec842e6f1b392863028781459/matplotlib-3.11.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:b4c78ceb2f11bcac7389d305cda17aeb1f4586a857854ab5780bd3dd8dbfc407", size = 10916701, upload-time = "2026-07-18T03:38:12.512Z" },
2383
+ { url = "https://files.pythonhosted.org/packages/bc/be/fa26ed085b41298f64a8f9b7592c671bbf1acc8b0df124c1c5de96b859f8/matplotlib-3.11.1-cp311-cp311-win_amd64.whl", hash = "sha256:7f33a781e12b1e53b278deb2f5373c2e55ec4f10727be3440c0cfb5cda9f944f", size = 9315331, upload-time = "2026-07-18T03:38:14.949Z" },
2384
+ { url = "https://files.pythonhosted.org/packages/b6/f3/eb5bdf3b6e191b200db298b08bbc1638b7f3c82cdc8680f9d88bf72559ae/matplotlib-3.11.1-cp311-cp311-win_arm64.whl", hash = "sha256:67e4c3cd578c65ebd81bdc09a1b6592ceafee6dfafe116dc85dfcb647b5bbb18", size = 9003475, upload-time = "2026-07-18T03:38:17.205Z" },
2385
+ { url = "https://files.pythonhosted.org/packages/f2/6c/7ef7ebcb2bd9739b2b66b18b076e077f44bb46fdbe28ca0506edb3c62c79/matplotlib-3.11.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:e15ef41507f3d525f46154ac9e3ae785dacde9f20e593a25de8986267892ef74", size = 9453849, upload-time = "2026-07-18T03:38:19.593Z" },
2386
+ { url = "https://files.pythonhosted.org/packages/eb/f8/6d0c312c8d9738e7d9677f09fe5c986b3239e651a7b73a2deb38b65e4a71/matplotlib-3.11.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:21a67b961a6d597bca54fae826cd20695ba4a6e4d05424a08da6e13e3176fd6b", size = 9283113, upload-time = "2026-07-18T03:38:21.95Z" },
2387
+ { url = "https://files.pythonhosted.org/packages/c9/cf/b4ad2cc81b6672ea29ea04e64e350a9f9b493b0908ccd884c67eeff8f7b2/matplotlib-3.11.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:ba8f811b8ddfac493734d6af0b2dff96919d0c28ca0d641858dab4262777c6ea", size = 10035615, upload-time = "2026-07-18T03:38:24.315Z" },
2388
+ { url = "https://files.pythonhosted.org/packages/88/90/4e10e033d9b66589d8ed98b84c95cdbb57033d57c1f41339d7393dbd2f2e/matplotlib-3.11.1-cp312-cp312-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c52f7ad20ef476806ed212380b1d54d20310c8b86bdc2c9a68b51f0024a44472", size = 10842559, upload-time = "2026-07-18T03:38:26.285Z" },
2389
+ { url = "https://files.pythonhosted.org/packages/88/eb/799612d0f8cd3e816a10fec59329fca52cd2353264df80378dfc541ae855/matplotlib-3.11.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:8b14eb22961fe865efb0e4ff167e333e428908b00115a8d800ccb65ee108e481", size = 10927532, upload-time = "2026-07-18T03:38:28.532Z" },
2390
+ { url = "https://files.pythonhosted.org/packages/88/89/56649bbaa2fd12e20f3be03dbcc135b0c8676d88bac17977599e3eb442a0/matplotlib-3.11.1-cp312-cp312-win_amd64.whl", hash = "sha256:88a2a27dd9691ae448dfae4b26f59036be90c3c28757edd3553a29559d00859f", size = 9333886, upload-time = "2026-07-18T03:38:30.477Z" },
2391
+ { url = "https://files.pythonhosted.org/packages/c1/11/4d124efbbad677b7b7552f6f85a3bd432d4232f95400cea98fcd2ae36ef3/matplotlib-3.11.1-cp312-cp312-win_arm64.whl", hash = "sha256:480194afceca4df2f137c2721227d3cba67121fbf4397b69cee7f83714b0a58a", size = 9007545, upload-time = "2026-07-18T03:38:32.833Z" },
2392
+ { url = "https://files.pythonhosted.org/packages/ee/38/ceb1d637c4db6d06141f3739e93af3321e7caaabe69b57ae48ffe3ee95b1/matplotlib-3.11.1-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:427258425f9a3fc4ed79a91f9e9b9aaf5a82cb6571e85dc14063cc6fbb993741", size = 9438045, upload-time = "2026-07-18T03:39:39.491Z" },
2393
+ { url = "https://files.pythonhosted.org/packages/89/25/72ad8b58602d3a6ef1dfc4b65ecd01634ab65a2bdf494c9fe0e966dbf081/matplotlib-3.11.1-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:1ac697e591c11b6ad04679a73c2d2f9980fe9d9f0311fb414a2e329706343dfb", size = 9266127, upload-time = "2026-07-18T03:39:41.597Z" },
2394
+ { url = "https://files.pythonhosted.org/packages/8a/6d/69552382fcc8e93d1f2763ef2665980a900a48b7f3a4c57ed290726d1cbc/matplotlib-3.11.1-pp311-pypy311_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:e4b9ac2f1f607ecda2af90a5232beee2af7582fce1cc30c4b6a1b012dc21ee99", size = 10019439, upload-time = "2026-07-18T03:39:43.78Z" },
2394
2395
  ]
2395
2396
 
2396
2397
  [[package]]
@@ -2804,8 +2805,14 @@ wheels = [
2804
2805
  name = "numexpr"
2805
2806
  version = "2.14.1"
2806
2807
  source = { registry = "https://pypi.org/simple" }
2808
+ resolution-markers = [
2809
+ "python_full_version < '3.11' and sys_platform == 'win32'",
2810
+ "python_full_version < '3.11' and sys_platform == 'darwin'",
2811
+ "python_full_version < '3.11' and sys_platform == 'linux'",
2812
+ "python_full_version < '3.11' and sys_platform != 'darwin' and sys_platform != 'linux' and sys_platform != 'win32'",
2813
+ ]
2807
2814
  dependencies = [
2808
- { name = "numpy" },
2815
+ { name = "numpy", marker = "python_full_version < '3.11'" },
2809
2816
  ]
2810
2817
  sdist = { url = "https://files.pythonhosted.org/packages/cb/2f/fdba158c9dbe5caca9c3eca3eaffffb251f2fb8674bf8e2d0aed5f38d319/numexpr-2.14.1.tar.gz", hash = "sha256:4be00b1086c7b7a5c32e31558122b7b80243fe098579b170967da83f3152b48b", size = 119400, upload-time = "2025-10-13T16:17:27.351Z" }
2811
2818
  wheels = [
@@ -2835,6 +2842,43 @@ wheels = [
2835
2842
  { url = "https://files.pythonhosted.org/packages/1f/67/ffe750b5452eb66de788c34e7d21ec6d886abb4d7c43ad1dc88ceb3d998f/numexpr-2.14.1-cp312-cp312-win_amd64.whl", hash = "sha256:fdd886f4b7dbaf167633ee396478f0d0aa58ea2f9e7ccc3c6431019623e8d68f", size = 160187, upload-time = "2025-10-13T16:17:11.974Z" },
2836
2843
  ]
2837
2844
 
2845
+ [[package]]
2846
+ name = "numexpr"
2847
+ version = "2.14.2"
2848
+ source = { registry = "https://pypi.org/simple" }
2849
+ resolution-markers = [
2850
+ "python_full_version >= '3.12' and sys_platform == 'win32'",
2851
+ "python_full_version == '3.11.*' and sys_platform == 'win32'",
2852
+ "python_full_version >= '3.11' and sys_platform == 'emscripten'",
2853
+ "python_full_version >= '3.11' and sys_platform == 'darwin'",
2854
+ "python_full_version >= '3.11' and sys_platform == 'linux'",
2855
+ "python_full_version >= '3.11' and sys_platform != 'darwin' and sys_platform != 'emscripten' and sys_platform != 'linux' and sys_platform != 'win32'",
2856
+ ]
2857
+ dependencies = [
2858
+ { name = "numpy", marker = "python_full_version >= '3.11'" },
2859
+ ]
2860
+ sdist = { url = "https://files.pythonhosted.org/packages/79/c4/27ea7849eb4a7e3b51db446b0414254326dba8c6bdee09b9f2abf963e55d/numexpr-2.14.2.tar.gz", hash = "sha256:e7144e83ea9e581f2273e0304f15836736c4e470e2bd2e378ce617662a1ca278", size = 121744, upload-time = "2026-07-18T10:52:43.185Z" }
2861
+ wheels = [
2862
+ { url = "https://files.pythonhosted.org/packages/b9/a3/1904a5928de2c16935172a54772082e6a64efa4e763ed829c2e9f23d8eb1/numexpr-2.14.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:2aa65ddc2243f19c6915f34ee0978b4a2df20f297230a793c4ee6d55f3472599", size = 164944, upload-time = "2026-07-18T10:51:37.875Z" },
2863
+ { url = "https://files.pythonhosted.org/packages/fb/03/533659d9c05c0aee359f29c6e1bb80f0b91848b75522bd9809861b0b0f25/numexpr-2.14.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:bf959e6df6cb603611c034b6cba7b03a361be0ad0b80b73f163fab95f5ccbb7f", size = 153218, upload-time = "2026-07-18T10:51:39.429Z" },
2864
+ { url = "https://files.pythonhosted.org/packages/cd/34/e20830b6388568c1a6fd1529953ccac09d7ed57eb79dacfd298646bd95c8/numexpr-2.14.2-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d534ecb456a4ae3995f99c8a5deb469bfff05d4ec610a7885c175c881d12f710", size = 453750, upload-time = "2026-07-18T10:51:40.735Z" },
2865
+ { url = "https://files.pythonhosted.org/packages/d6/15/9a7bf92b7c8047157fd96bc42ff6b0a20351f43aa58b9f61eb8f5ff3048b/numexpr-2.14.2-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f41170e9d0dbba76851e35d80cfa9f4ca5fe78628c5bf24d941cf3364940ab7a", size = 443546, upload-time = "2026-07-18T10:51:41.95Z" },
2866
+ { url = "https://files.pythonhosted.org/packages/86/ed/a2aaca2a65d5aa04379d3bcc8360c067aa2503fbad2c88c0709f1b3e1e6c/numexpr-2.14.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:6acafb2fdbeaaa6681a8f1a1d8b3f7dcd33704baace7057b950754b258be7c43", size = 1418879, upload-time = "2026-07-18T10:51:43.315Z" },
2867
+ { url = "https://files.pythonhosted.org/packages/62/6d/dde6da68ef817d9aa0995a0ecdfb9b0ba5745688fb324b96b2250bb00131/numexpr-2.14.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:7ca9e71195b36cc7aeafe97347549e1e1c1e889ff700238782ef6447651ec26d", size = 1465942, upload-time = "2026-07-18T10:51:44.609Z" },
2868
+ { url = "https://files.pythonhosted.org/packages/96/2f/5b352550476d10b85e4198bd045c155ca63a55853aeb11861996f05707a0/numexpr-2.14.2-cp311-cp311-win32.whl", hash = "sha256:779129d50974e7d6d6581d322f75b8f8375e96215b6861a2d5460347997ef649", size = 161260, upload-time = "2026-07-18T10:51:45.861Z" },
2869
+ { url = "https://files.pythonhosted.org/packages/44/5e/00d696bca8bb9cad9c8a775ae5c1559e4a7cc083029f274c14cae5bc52fa/numexpr-2.14.2-cp311-cp311-win_amd64.whl", hash = "sha256:2f132777d7d425471c458af5617e023402f13f5006301eacf8a1a6e7118ea70c", size = 157406, upload-time = "2026-07-18T10:51:47.065Z" },
2870
+ { url = "https://files.pythonhosted.org/packages/23/00/fd8caf2a08304e4d2bc64031ef11da3ccd863853d277f424adf91d44371f/numexpr-2.14.2-cp311-cp311-win_arm64.whl", hash = "sha256:f1de5c88515ed9fbcad42699a0e2b5821b4d0f0adb0da6fb7e009e5cb19d8493", size = 148781, upload-time = "2026-07-18T10:51:48.1Z" },
2871
+ { url = "https://files.pythonhosted.org/packages/09/fd/3e7ca4328c22b28717cfe05cd23ca35ffd84e4ca36c3da004323528e9e20/numexpr-2.14.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:606ceaf5722e295ef965ca591736fc26d9e5f13ad950a479e64cead1947f8a3d", size = 164757, upload-time = "2026-07-18T10:51:49.05Z" },
2872
+ { url = "https://files.pythonhosted.org/packages/ed/5c/9780d48c4d5effcf55fc7ab7c5651ed82b43250ac8410cce4ef1e97583ed/numexpr-2.14.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:790da022539fe7c37dc893acf530a91c2ca6964d7ba11f464131383729d058f3", size = 153507, upload-time = "2026-07-18T10:51:50.273Z" },
2873
+ { url = "https://files.pythonhosted.org/packages/41/13/ed5efda74ace9a7e2e933476b85bba6d00f2ebf6b833ef59a796ec9af88c/numexpr-2.14.2-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:327be9ee62251c173236dc620147ff2d0e732a32f5bad918d78a10082f502f63", size = 455373, upload-time = "2026-07-18T10:51:51.466Z" },
2874
+ { url = "https://files.pythonhosted.org/packages/ea/11/e8953226d658ae67e3e002abaa60a101c693f9c57d74974001729afab5ef/numexpr-2.14.2-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d6a5d8fc7016bf6f6e1808b011510aa7c3bd75ec1407f7650874ec591db59f5e", size = 445187, upload-time = "2026-07-18T10:51:52.849Z" },
2875
+ { url = "https://files.pythonhosted.org/packages/b2/f7/f51b7e10c312bd9617df829e063c87a6d443fd97af54688282ba2b11b1fd/numexpr-2.14.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:4b1ff261c3e69c4c59578d3a9ca6132603619d38ae1abe73325563bed3b9bbaf", size = 1420426, upload-time = "2026-07-18T10:51:54.079Z" },
2876
+ { url = "https://files.pythonhosted.org/packages/14/bf/21b4e362039ba52f9033a3f57d68160c0829c9c8d66fa7b443b82491322c/numexpr-2.14.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:8b8384592c49cb15a91caa54e2cd84d1ce18edb7af030bb76cd29b52e5dc155d", size = 1467554, upload-time = "2026-07-18T10:51:55.391Z" },
2877
+ { url = "https://files.pythonhosted.org/packages/2b/75/0856b1add4e5a7741b80b615f3faace8e3cfffe11e22b6a940ebf25443aa/numexpr-2.14.2-cp312-cp312-win32.whl", hash = "sha256:41cdeacf1b4e51c1143983ea61fcee68139ca47222b55a9265b4fa73826c4260", size = 161441, upload-time = "2026-07-18T10:51:56.503Z" },
2878
+ { url = "https://files.pythonhosted.org/packages/a3/78/c87a88b8e63b5f78c67d555afebefafe81f6e3d98640b4bc1c125d76c9d3/numexpr-2.14.2-cp312-cp312-win_amd64.whl", hash = "sha256:8fc55d14bcf17b3fe69213bea14f999451892b4690717008c66f2edfd6a085ce", size = 157563, upload-time = "2026-07-18T10:51:57.521Z" },
2879
+ { url = "https://files.pythonhosted.org/packages/15/37/eea56d5ed1ae5252447f45bb461930eab66338eeab32e533aceb080db0bb/numexpr-2.14.2-cp312-cp312-win_arm64.whl", hash = "sha256:806a4471310fe20aa7cb1b2816a6f5e508073a1ad1c2e18041b83e57066fad6a", size = 148820, upload-time = "2026-07-18T10:51:58.536Z" },
2880
+ ]
2881
+
2838
2882
  [[package]]
2839
2883
  name = "numpy"
2840
2884
  version = "1.26.4"
@@ -3204,11 +3248,11 @@ wheels = [
3204
3248
 
3205
3249
  [[package]]
3206
3250
  name = "platformdirs"
3207
- version = "4.10.0"
3251
+ version = "4.11.0"
3208
3252
  source = { registry = "https://pypi.org/simple" }
3209
- sdist = { url = "https://files.pythonhosted.org/packages/d7/47/e4501f49c178ae1d9f4a75073fda4204f52647993f075a9db4d14930e0c5/platformdirs-4.10.0.tar.gz", hash = "sha256:31e761a6a0ca04faf7353ea759bdba55652be214725111e5aac52dfa29d4bef7", size = 31224, upload-time = "2026-05-28T03:32:53.587Z" }
3253
+ sdist = { url = "https://files.pythonhosted.org/packages/78/9b/560e4be8e26f6fd133a03630a8df0c663b9e8d61b4ade152b72005aec83b/platformdirs-4.11.0.tar.gz", hash = "sha256:0555d18370482847566ffabcaa53ad7c6c1c29f195989ae1ed634a05f76ea1e0", size = 31953, upload-time = "2026-07-21T13:09:36.565Z" }
3210
3254
  wheels = [
3211
- { url = "https://files.pythonhosted.org/packages/81/e6/cd9575ac904136b3cbf7aa7ee819ef86eedb7274e46f230e94ea4342e729/platformdirs-4.10.0-py3-none-any.whl", hash = "sha256:fb516cdb12eb0d857d0cd85a7c57cea4d060bee4578d6cf5a14dfdf8cbf8784a", size = 22743, upload-time = "2026-05-28T03:32:52.175Z" },
3255
+ { url = "https://files.pythonhosted.org/packages/7d/68/d8d58938dfb1370b266a1a729e6d77a985be23689a0496498ee17b2cbf90/platformdirs-4.11.0-py3-none-any.whl", hash = "sha256:360ccded2b7fce0af0ff80cc8f5942a1c5d99b0e856033acb030bfc634709e74", size = 23247, upload-time = "2026-07-21T13:09:35.422Z" },
3212
3256
  ]
3213
3257
 
3214
3258
  [[package]]
@@ -3235,30 +3279,30 @@ wheels = [
3235
3279
 
3236
3280
  [[package]]
3237
3281
  name = "polars"
3238
- version = "1.42.1"
3282
+ version = "1.43.0"
3239
3283
  source = { registry = "https://pypi.org/simple" }
3240
3284
  dependencies = [
3241
3285
  { name = "polars-runtime-32" },
3242
3286
  ]
3243
- sdist = { url = "https://files.pythonhosted.org/packages/27/99/fe77f10a13a778705ef05b499fc708c9a0b0a3680d9eb6bc6e1b6a6b9914/polars-1.42.1.tar.gz", hash = "sha256:2fe94f3059334650bd850ae19a9c165dcd5d9cb12cd95ea04de2201662e70e8a", size = 741532, upload-time = "2026-06-30T04:57:51.504Z" }
3287
+ sdist = { url = "https://files.pythonhosted.org/packages/66/5b/5d0f0aa53c6e9a8ecbc99ff502edcf9584e5d08ab34ea407c086999103d5/polars-1.43.0.tar.gz", hash = "sha256:bb2c67553e4968c18dfe268a88ff9a5790d5c2e0b7ea7efe97640b9a90438c88", size = 749537, upload-time = "2026-07-21T04:30:25.966Z" }
3244
3288
  wheels = [
3245
- { url = "https://files.pythonhosted.org/packages/be/6a/edd939cc6fa04b6415aaa9bf19720fc74ead81234b3d38542e0005816d4d/polars-1.42.1-py3-none-any.whl", hash = "sha256:3c0c65cdfa21a621650c4bdcbbccf93964d052fd766c3e70e84a55d961c259fd", size = 837622, upload-time = "2026-06-30T04:56:34.686Z" },
3289
+ { url = "https://files.pythonhosted.org/packages/76/28/a8eac2c1d1b2d2a4ba2eb745921616d863185d94b1afd91cbb07af9ef21a/polars-1.43.0-py3-none-any.whl", hash = "sha256:c49078b14e2d6b8ff5cc5b78b6d9638603ea5dffafb889d9204818822f55b813", size = 846493, upload-time = "2026-07-21T04:29:06.68Z" },
3246
3290
  ]
3247
3291
 
3248
3292
  [[package]]
3249
3293
  name = "polars-runtime-32"
3250
- version = "1.42.1"
3294
+ version = "1.43.0"
3251
3295
  source = { registry = "https://pypi.org/simple" }
3252
- sdist = { url = "https://files.pythonhosted.org/packages/1f/59/15bcc4dac380c6d63efa5446d8317f22671cbd6c9dadd576bd17a334c45a/polars_runtime_32-1.42.1.tar.gz", hash = "sha256:4d4809e1c1b9a6611f6944f27b24abea902b5159e6b6fa262fd716e947af5afd", size = 3045460, upload-time = "2026-06-30T04:57:52.866Z" }
3296
+ sdist = { url = "https://files.pythonhosted.org/packages/86/96/7e714cad082e9e6aaebb8886fcb1b0220d5c35149d4c8d3466bd7e7d581e/polars_runtime_32-1.43.0.tar.gz", hash = "sha256:5fb47a3a883402e62eab2fde5922f78c531d037aeece3640c15225f39228621e", size = 3090044, upload-time = "2026-07-21T04:30:27.185Z" }
3253
3297
  wheels = [
3254
- { url = "https://files.pythonhosted.org/packages/62/29/16ff6e4e91d71e530d3581f45e342a9cc35072ac6b31dcbc2fa33de2569e/polars_runtime_32-1.42.1-cp310-abi3-macosx_10_12_x86_64.whl", hash = "sha256:bbdc26d68ee5b23b0ce227fa0599220aa35b77c826b6b0a6b2d8e7f6c1c36974", size = 53117325, upload-time = "2026-06-30T04:56:37.972Z" },
3255
- { url = "https://files.pythonhosted.org/packages/04/8e/4f8296fcfd1347f1351342fecf13bf2430d7efbae2f1f45964ec7930a99e/polars_runtime_32-1.42.1-cp310-abi3-macosx_11_0_arm64.whl", hash = "sha256:f6c0288be940b607dc4a7476c01e67fb6bbee93f5f1dd42c64970274c71008ba", size = 47446251, upload-time = "2026-06-30T04:56:41.459Z" },
3256
- { url = "https://files.pythonhosted.org/packages/88/2e/0d66a7deadc453b890c3391034ca8ab4b05d0beaebbb92a7d65199fba61b/polars_runtime_32-1.42.1-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:635d9dbcae2302ae223afb395d5cd220bffa61a53d0ab6871d17c8bc830101cf", size = 51359402, upload-time = "2026-06-30T04:56:44.595Z" },
3257
- { url = "https://files.pythonhosted.org/packages/5d/10/ffb85fa380bc9c9000dc35f40f44954dde49023018501c54faab94b3a39e/polars_runtime_32-1.42.1-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d059e8e53cc114ff82f9bd791fd341dc53534a2c745e6f6aa37594c3a93f01fe", size = 57302723, upload-time = "2026-06-30T04:56:47.609Z" },
3258
- { url = "https://files.pythonhosted.org/packages/c2/63/ca50adc62e44224ca5c622a842ba6f35ee87d1d40ef0df7ea2ed6c6edb08/polars_runtime_32-1.42.1-cp310-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:f91f0b13588324905682809d270e1de5f1990c908721c8527657d77a044c9919", size = 51515673, upload-time = "2026-06-30T04:56:50.88Z" },
3259
- { url = "https://files.pythonhosted.org/packages/63/c3/08fbbf38deaa17bf34a601d327cb7451074098673c78b7c1a8538dde9794/polars_runtime_32-1.42.1-cp310-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:8b8bf972d99d48aaaa2582e2bce966a6f43bc815bd8725d15f5cab9e2fb15d17", size = 55217259, upload-time = "2026-06-30T04:56:53.834Z" },
3260
- { url = "https://files.pythonhosted.org/packages/d1/0e/51db89361668fe077a835fc579277f824ba526e7daf7b94d23d25439e0d0/polars_runtime_32-1.42.1-cp310-abi3-win_amd64.whl", hash = "sha256:e9364c26da389a8b7339e4d29e20a3d12af730247e6ed3b7804bddce2477f428", size = 52715432, upload-time = "2026-06-30T04:56:57.109Z" },
3261
- { url = "https://files.pythonhosted.org/packages/76/c5/2fb8592d691bd114de25d9c84300b23541dca7060eac11d7b4bed0327786/polars_runtime_32-1.42.1-cp310-abi3-win_arm64.whl", hash = "sha256:7051226e6b42ffc395a7a9190377cd28649fbfb991b8f85c6271f4e1cfb736fb", size = 46718300, upload-time = "2026-06-30T04:56:59.855Z" },
3298
+ { url = "https://files.pythonhosted.org/packages/0f/14/9b1f5eb1c5104ba1ceb380a7308ffcd979f3ce1df86e76293062698f2ff1/polars_runtime_32-1.43.0-cp310-abi3-macosx_10_12_x86_64.whl", hash = "sha256:6707193d30a7135bce0424304f76d8145270527444097548e794ad8d26823b70", size = 53059463, upload-time = "2026-07-21T04:29:09.194Z" },
3299
+ { url = "https://files.pythonhosted.org/packages/ca/14/73d77d1c0c928eb599d9516d874af0cd2b6225201e1327a6c4857e6776d0/polars_runtime_32-1.43.0-cp310-abi3-macosx_11_0_arm64.whl", hash = "sha256:78ca2f97740b2a6beb36eb112749280b5e08750c60f53c08d2feffebdba9d35a", size = 47499586, upload-time = "2026-07-21T04:29:13.229Z" },
3300
+ { url = "https://files.pythonhosted.org/packages/80/b1/98278fa796f93d0975fd3fe1d4ab4031707d4a9f1da44c21c29996b62c73/polars_runtime_32-1.43.0-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4ffa99bb2c7ee0a9392ae50b350af0ed17acf0519d15c75fe223021798566174", size = 51326702, upload-time = "2026-07-21T04:29:16.084Z" },
3301
+ { url = "https://files.pythonhosted.org/packages/ab/7d/24ae73389aac03296925973c4e2cbe2e4982e859b9fad69eb1a72b9026fa/polars_runtime_32-1.43.0-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3ecc8feaf04de5989a29245885921db612ef1ce9065e5cb6ec37495acfa55bba", size = 57266705, upload-time = "2026-07-21T04:29:19.288Z" },
3302
+ { url = "https://files.pythonhosted.org/packages/5c/49/2026be1f7b51242ad62e08b20728462558e161fb84b564e5b986f2b38664/polars_runtime_32-1.43.0-cp310-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:01e1471a5ee161a969c7a96991d8e5d20b97a0b7fe075df9c7a01f52a49c5ac2", size = 51484129, upload-time = "2026-07-21T04:29:22.639Z" },
3303
+ { url = "https://files.pythonhosted.org/packages/db/e2/047c7695f08a9b18614c0e1ec5e70a754455542a21a6d52955f7f05c6268/polars_runtime_32-1.43.0-cp310-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:9cd8b813afe67d59e87027dedcaf5c6a06fe602472fd74e1a49f4bafea47259c", size = 55169401, upload-time = "2026-07-21T04:29:25.902Z" },
3304
+ { url = "https://files.pythonhosted.org/packages/92/dc/bfd2533c487563c7a21ab7d7af3d78f820b0236e14dc5ee63d46188cd275/polars_runtime_32-1.43.0-cp310-abi3-win_amd64.whl", hash = "sha256:41a75fb3cb4cc574eb21801383578f75cfc374597c22322ef457ab7bac8a3301", size = 52541527, upload-time = "2026-07-21T04:29:29.162Z" },
3305
+ { url = "https://files.pythonhosted.org/packages/46/d7/5c47f1bf57479d1671669af9c421f9abf4986b2ddaa64c177244ff811de0/polars_runtime_32-1.43.0-cp310-abi3-win_arm64.whl", hash = "sha256:c285e598dd91e08560e519275b8b8108adbafb438d218a175ebe073dbc2027fb", size = 46552281, upload-time = "2026-07-21T04:29:32.224Z" },
3262
3306
  ]
3263
3307
 
3264
3308
  [[package]]
@@ -3797,15 +3841,15 @@ wheels = [
3797
3841
 
3798
3842
  [[package]]
3799
3843
  name = "python-discovery"
3800
- version = "1.4.4"
3844
+ version = "1.5.0"
3801
3845
  source = { registry = "https://pypi.org/simple" }
3802
3846
  dependencies = [
3803
3847
  { name = "filelock" },
3804
3848
  { name = "platformdirs" },
3805
3849
  ]
3806
- sdist = { url = "https://files.pythonhosted.org/packages/4c/81/58c70036dffeccb7fe7d79d6260c69f7a28272bbd3909c29a01ea9422744/python_discovery-1.4.4.tar.gz", hash = "sha256:5cad33982d412c1f3ffb8f9ca4ea292c9680bca3942451d30b69c37fce53a4a3", size = 72212, upload-time = "2026-07-08T23:06:50.691Z" }
3850
+ sdist = { url = "https://files.pythonhosted.org/packages/f1/51/276f964496a5714ab9f320896195639086881c2b39c03b5ad13de84acbb8/python_discovery-1.5.0.tar.gz", hash = "sha256:3e014c6327154d3dda27939a9a0dc9c5c000439f1906d3f303b48f984bd2ecef", size = 72483, upload-time = "2026-07-21T13:14:14.641Z" }
3807
3851
  wheels = [
3808
- { url = "https://files.pythonhosted.org/packages/9d/ae/84bc0d2440c95772272bb6f4b3d09ccf08b2898fce89b3d4f969a9fc74e9/python_discovery-1.4.4-py3-none-any.whl", hash = "sha256:abebe9120b43453b68c908acfb1e72a19d1a959ed2cb620ad38fc57d08056dbe", size = 34181, upload-time = "2026-07-08T23:06:49.402Z" },
3852
+ { url = "https://files.pythonhosted.org/packages/c7/7b/14882602ddee241d7984a742fcb423cb4a30fb0d6efc546ac3129fba475a/python_discovery-1.5.0-py3-none-any.whl", hash = "sha256:70c4fc61b4e7404e44f01d6fc44a715c4d685ca6cea83d295922f05891877c98", size = 34205, upload-time = "2026-07-21T13:14:13.398Z" },
3809
3853
  ]
3810
3854
 
3811
3855
  [[package]]
@@ -4378,7 +4422,7 @@ version = "0.13.2"
4378
4422
  source = { registry = "https://pypi.org/simple" }
4379
4423
  dependencies = [
4380
4424
  { name = "matplotlib", version = "3.10.9", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" },
4381
- { name = "matplotlib", version = "3.11.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" },
4425
+ { name = "matplotlib", version = "3.11.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" },
4382
4426
  { name = "numpy" },
4383
4427
  { name = "pandas", version = "2.3.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" },
4384
4428
  { name = "pandas", version = "3.0.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" },
@@ -4452,11 +4496,11 @@ wheels = [
4452
4496
 
4453
4497
  [[package]]
4454
4498
  name = "soupsieve"
4455
- version = "2.8.4"
4499
+ version = "2.9.1"
4456
4500
  source = { registry = "https://pypi.org/simple" }
4457
- sdist = { url = "https://files.pythonhosted.org/packages/47/2c/0a5f6f8ee0d5589e48c7640213ed5175d52cf540a06725b628cc1a45d6ce/soupsieve-2.8.4.tar.gz", hash = "sha256:e121fd02e975c695e4e9e8774a5ee35d74714b59307868dcc5319ad2d9e3328e", size = 121110, upload-time = "2026-05-24T13:55:57.154Z" }
4501
+ sdist = { url = "https://files.pythonhosted.org/packages/d9/38/e12680bbe6b4f8f3d17adcaf38d26850aa756c85cf4a80e79fc12a018fe8/soupsieve-2.9.1.tar.gz", hash = "sha256:c33e6605bbc71dd628b00c632d58ae607c22bade247e52553928f83bbb75b4ba", size = 122261, upload-time = "2026-07-21T16:57:17.452Z" }
4458
4502
  wheels = [
4459
- { url = "https://files.pythonhosted.org/packages/5e/f5/0c41cb68dcae6b7de4fac4188a3a9589e21fb31df21ea3a2e888db95e6c9/soupsieve-2.8.4-py3-none-any.whl", hash = "sha256:e7e6b0769c8f51ed59acab6e994b00621096cfb1c640a7509295987388fbaf65", size = 37304, upload-time = "2026-05-24T13:55:55.406Z" },
4503
+ { url = "https://files.pythonhosted.org/packages/0f/2c/437fe806897c2d6cfdc3ee43a18da8bf8e568530a4ae9bac781541ca9896/soupsieve-2.9.1-py3-none-any.whl", hash = "sha256:4f4477399246b7a0c720a88ca2454b11cd6bb9ae4c9d170140786e916776c14c", size = 37404, upload-time = "2026-07-21T16:57:16.421Z" },
4460
4504
  ]
4461
4505
 
4462
4506
  [[package]]
@@ -4519,7 +4563,7 @@ resolution-markers = [
4519
4563
  ]
4520
4564
  dependencies = [
4521
4565
  { name = "blosc2", version = "4.3.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" },
4522
- { name = "numexpr", marker = "python_full_version < '3.11'" },
4566
+ { name = "numexpr", version = "2.14.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" },
4523
4567
  { name = "numpy", marker = "python_full_version < '3.11'" },
4524
4568
  { name = "packaging", marker = "python_full_version < '3.11'" },
4525
4569
  { name = "py-cpuinfo", marker = "python_full_version < '3.11'" },
@@ -4558,7 +4602,7 @@ resolution-markers = [
4558
4602
  ]
4559
4603
  dependencies = [
4560
4604
  { name = "blosc2", version = "4.9.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" },
4561
- { name = "numexpr", marker = "python_full_version >= '3.11'" },
4605
+ { name = "numexpr", version = "2.14.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" },
4562
4606
  { name = "numpy", marker = "python_full_version >= '3.11'" },
4563
4607
  { name = "packaging", marker = "python_full_version >= '3.11'" },
4564
4608
  { name = "py-cpuinfo", marker = "python_full_version >= '3.11'" },
@@ -4609,7 +4653,7 @@ wheels = [
4609
4653
 
4610
4654
  [[package]]
4611
4655
  name = "tlpytools"
4612
- version = "0.2.3"
4656
+ version = "0.2.5"
4613
4657
  source = { editable = "." }
4614
4658
  dependencies = [
4615
4659
  { name = "azure-core" },
@@ -4621,6 +4665,8 @@ dependencies = [
4621
4665
  { name = "cryptography" },
4622
4666
  { name = "cryptpandas" },
4623
4667
  { name = "ipykernel" },
4668
+ { name = "matplotlib", version = "3.10.9", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" },
4669
+ { name = "matplotlib", version = "3.11.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" },
4624
4670
  { name = "notebook" },
4625
4671
  { name = "numpy" },
4626
4672
  { name = "openmatrix" },
@@ -4703,6 +4749,7 @@ requires-dist = [
4703
4749
  { name = "geopandas", marker = "extra == 'dev'", specifier = ">=0.13.0" },
4704
4750
  { name = "ipykernel", specifier = ">=7.2.0" },
4705
4751
  { name = "kiwisolver", marker = "extra == 'dev'", specifier = ">=1.4.0" },
4752
+ { name = "matplotlib", specifier = ">=3.10.9" },
4706
4753
  { name = "mypy", marker = "extra == 'dev'", specifier = ">=1.5.0" },
4707
4754
  { name = "notebook", specifier = ">=7.5.6" },
4708
4755
  { name = "numpy", specifier = ">=1.18" },
@@ -4882,7 +4929,7 @@ wheels = [
4882
4929
 
4883
4930
  [[package]]
4884
4931
  name = "virtualenv"
4885
- version = "21.6.1"
4932
+ version = "21.7.0"
4886
4933
  source = { registry = "https://pypi.org/simple" }
4887
4934
  dependencies = [
4888
4935
  { name = "distlib" },
@@ -4891,9 +4938,9 @@ dependencies = [
4891
4938
  { name = "python-discovery" },
4892
4939
  { name = "typing-extensions", marker = "python_full_version < '3.11'" },
4893
4940
  ]
4894
- sdist = { url = "https://files.pythonhosted.org/packages/34/d9/b477fddb68840b570af8b22afe9b035cbc277b5fb7b33dea390617a8b10f/virtualenv-21.6.1.tar.gz", hash = "sha256:15f978b7cd329f24855ff4a0c4b4899cc7678589f49adbdcbbb4d3232e641128", size = 5526620, upload-time = "2026-07-10T19:33:53.312Z" }
4941
+ sdist = { url = "https://files.pythonhosted.org/packages/fe/25/e367a7229b0914772ca8d81b41fde012d9feda68523b52644a571bb21ce8/virtualenv-21.7.0.tar.gz", hash = "sha256:7f9519b9432ff11b6e1a3e94061664efc2ff99ea21780e3cf4f6bd0a5da8b37c", size = 5527510, upload-time = "2026-07-21T13:12:14.109Z" }
4895
4942
  wheels = [
4896
- { url = "https://files.pythonhosted.org/packages/c1/7c/4e7225d46d634a0d8d534dd8a6ce0c319d09b4d0cf0337eb314ca4789d8c/virtualenv-21.6.1-py3-none-any.whl", hash = "sha256:afe991df855715a2b2f60edfcc0107ef95a79fdfd8cb4cdaa71603d1c12e463b", size = 5506392, upload-time = "2026-07-10T19:33:51.629Z" },
4943
+ { url = "https://files.pythonhosted.org/packages/a5/7a/ae29312b1e88a22e81f5d21fc11526d2a114089776c2550d2b205b6c2a47/virtualenv-21.7.0-py3-none-any.whl", hash = "sha256:a8370c1c5530fbabf955e40b8fbbc68a431648b10f9433faa587db30a06e51dd", size = 5507078, upload-time = "2026-07-21T13:12:12.136Z" },
4897
4944
  ]
4898
4945
 
4899
4946
  [[package]]
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