tlpytools 0.2.0__tar.gz → 0.2.2__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.
- {tlpytools-0.2.0 → tlpytools-0.2.2}/.github/copilot-instructions.md +2 -2
- {tlpytools-0.2.0 → tlpytools-0.2.2}/.github/workflows/deploy.yml +1 -1
- {tlpytools-0.2.0 → tlpytools-0.2.2}/CHANGELOG.md +17 -0
- {tlpytools-0.2.0 → tlpytools-0.2.2}/DEVELOPER_GUIDE.md +4 -4
- {tlpytools-0.2.0 → tlpytools-0.2.2}/PKG-INFO +1 -1
- {tlpytools-0.2.0 → tlpytools-0.2.2}/pyproject.toml +1 -1
- {tlpytools-0.2.0 → tlpytools-0.2.2}/src/tlpytools/__init__.py +1 -1
- {tlpytools-0.2.0 → tlpytools-0.2.2}/src/tlpytools/orca/orchestrator.py +71 -27
- {tlpytools-0.2.0 → tlpytools-0.2.2}/uv.lock +1 -1
- {tlpytools-0.2.0 → tlpytools-0.2.2}/.env.example +0 -0
- {tlpytools-0.2.0 → tlpytools-0.2.2}/.github/skills/README.md +0 -0
- {tlpytools-0.2.0 → tlpytools-0.2.2}/.github/skills/prepare-official-release/SKILL.md +0 -0
- {tlpytools-0.2.0 → tlpytools-0.2.2}/.github/workflows/code-formatting-pr.yml +0 -0
- {tlpytools-0.2.0 → tlpytools-0.2.2}/.github/workflows/code-formatting.yml +0 -0
- {tlpytools-0.2.0 → tlpytools-0.2.2}/.github/workflows/test.yml +0 -0
- {tlpytools-0.2.0 → tlpytools-0.2.2}/.gitignore +0 -0
- {tlpytools-0.2.0 → tlpytools-0.2.2}/.pre-commit-config.yaml +0 -0
- {tlpytools-0.2.0 → tlpytools-0.2.2}/.python-version +0 -0
- {tlpytools-0.2.0 → tlpytools-0.2.2}/ENVIRONMENT_VARIABLES.md +0 -0
- {tlpytools-0.2.0 → tlpytools-0.2.2}/Makefile +0 -0
- {tlpytools-0.2.0 → tlpytools-0.2.2}/README.md +0 -0
- {tlpytools-0.2.0 → tlpytools-0.2.2}/docs/adls_server.md +0 -0
- {tlpytools-0.2.0 → tlpytools-0.2.2}/docs/azure_credential_manager.md +0 -0
- {tlpytools-0.2.0 → tlpytools-0.2.2}/docs/diagrams/README.md +0 -0
- {tlpytools-0.2.0 → tlpytools-0.2.2}/docs/diagrams/orca_cloud_workflow.drawio +0 -0
- {tlpytools-0.2.0 → tlpytools-0.2.2}/docs/diagrams/orca_detailed_steps.drawio +0 -0
- {tlpytools-0.2.0 → tlpytools-0.2.2}/docs/diagrams/orca_file_structure.drawio +0 -0
- {tlpytools-0.2.0 → tlpytools-0.2.2}/docs/diagrams/orca_local_workflow.drawio +0 -0
- {tlpytools-0.2.0 → tlpytools-0.2.2}/docs/diagrams/orca_main_features.drawio +0 -0
- {tlpytools-0.2.0 → tlpytools-0.2.2}/docs/unified_logging.md +0 -0
- {tlpytools-0.2.0 → tlpytools-0.2.2}/requirements.txt +0 -0
- {tlpytools-0.2.0 → tlpytools-0.2.2}/src/examples/batchtask.py +0 -0
- {tlpytools-0.2.0 → tlpytools-0.2.2}/src/examples/data_files/example.csv +0 -0
- {tlpytools-0.2.0 → tlpytools-0.2.2}/src/examples/mydataproject.py +0 -0
- {tlpytools-0.2.0 → tlpytools-0.2.2}/src/examples/readwritedata.py +0 -0
- {tlpytools-0.2.0 → tlpytools-0.2.2}/src/examples/unified_logging.py +0 -0
- {tlpytools-0.2.0 → tlpytools-0.2.2}/src/tlpytools/adls_server.py +0 -0
- {tlpytools-0.2.0 → tlpytools-0.2.2}/src/tlpytools/azure_credential.py +0 -0
- {tlpytools-0.2.0 → tlpytools-0.2.2}/src/tlpytools/config.py +0 -0
- {tlpytools-0.2.0 → tlpytools-0.2.2}/src/tlpytools/data.py +0 -0
- {tlpytools-0.2.0 → tlpytools-0.2.2}/src/tlpytools/data_store.py +0 -0
- {tlpytools-0.2.0 → tlpytools-0.2.2}/src/tlpytools/env_config.py +0 -0
- {tlpytools-0.2.0 → tlpytools-0.2.2}/src/tlpytools/log.py +0 -0
- {tlpytools-0.2.0 → tlpytools-0.2.2}/src/tlpytools/orca/README.md +0 -0
- {tlpytools-0.2.0 → tlpytools-0.2.2}/src/tlpytools/orca/__init__.py +0 -0
- {tlpytools-0.2.0 → tlpytools-0.2.2}/src/tlpytools/orca/__main__.py +0 -0
- {tlpytools-0.2.0 → tlpytools-0.2.2}/src/tlpytools/orca/batch_task_runner.py +0 -0
- {tlpytools-0.2.0 → tlpytools-0.2.2}/src/tlpytools/orca/cli.py +0 -0
- {tlpytools-0.2.0 → tlpytools-0.2.2}/src/tlpytools/orca/orca_model_config_barebone.yaml +0 -0
- {tlpytools-0.2.0 → tlpytools-0.2.2}/src/tlpytools/orca/orca_model_config_example.yaml +0 -0
- {tlpytools-0.2.0 → tlpytools-0.2.2}/src/tlpytools/sql_server.py +0 -0
- {tlpytools-0.2.0 → tlpytools-0.2.2}/tests/README.md +0 -0
- {tlpytools-0.2.0 → tlpytools-0.2.2}/tests/__init__.py +0 -0
- {tlpytools-0.2.0 → tlpytools-0.2.2}/tests/conftest.py +0 -0
- {tlpytools-0.2.0 → tlpytools-0.2.2}/tests/run_tests.py +0 -0
- {tlpytools-0.2.0 → tlpytools-0.2.2}/tests/test_azure_credential.py +0 -0
- {tlpytools-0.2.0 → tlpytools-0.2.2}/tests/test_basic.py +0 -0
- {tlpytools-0.2.0 → tlpytools-0.2.2}/tests/test_core.py +0 -0
- {tlpytools-0.2.0 → tlpytools-0.2.2}/tests/test_orca_integration.py +0 -0
- {tlpytools-0.2.0 → tlpytools-0.2.2}/tests/test_orca_unit.py +0 -0
|
@@ -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.
|
|
102
|
-
- `dist/tlpytools-0.2.
|
|
101
|
+
- `dist/tlpytools-0.2.2.tar.gz`
|
|
102
|
+
- `dist/tlpytools-0.2.2-py3-none-any.whl`
|
|
103
103
|
|
|
104
104
|
### 5) Run
|
|
105
105
|
- ORCA CLI (module form):
|
|
@@ -2,6 +2,23 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to TLPyTools will be documented in this file.
|
|
4
4
|
|
|
5
|
+
## [0.2.2]
|
|
6
|
+
|
|
7
|
+
### Fixed
|
|
8
|
+
* Fix python path leaks by cleaning up PYTHONPATH and PYTHONHOME during sub component model runs
|
|
9
|
+
* Clear stale errors when resuming or starting new runs on old scenario folders
|
|
10
|
+
|
|
11
|
+
## [0.2.1]
|
|
12
|
+
|
|
13
|
+
### Changed
|
|
14
|
+
- **ORCA logger naming improvement:**
|
|
15
|
+
- Replaced random UUID-based logger name with a git-aware identifier resolved from the ORCA project working directory
|
|
16
|
+
- Added `_resolve_logger_name()` method to `OrcaLogger` with the following priority:
|
|
17
|
+
1. Git tag pointing at HEAD → `orca_{tag}` (e.g. `orca_v0.3.0`)
|
|
18
|
+
2. Git short SHA (first 7 characters) → `orca_{sha}` (e.g. `orca_a1b2c3d`)
|
|
19
|
+
3. Random session UUID fallback → `session_{uuid8}` (e.g. `session_03d2bb45`)
|
|
20
|
+
- Git version is resolved from `os.getcwd()` (the user's project folder) rather than the tlpytools package directory
|
|
21
|
+
|
|
5
22
|
## [0.2.0]
|
|
6
23
|
|
|
7
24
|
### Changed
|
|
@@ -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.
|
|
203
|
+
- **Version number**: Enter the new version (e.g., `0.2.2`)
|
|
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.
|
|
222
|
+
pip install tlpytools==0.2.2 # Replace with your version
|
|
223
223
|
|
|
224
224
|
# Test installation in a fresh environment
|
|
225
225
|
python -c "import tlpytools; print(tlpytools.__version__)"
|
|
@@ -235,8 +235,8 @@ TLPyTools follows semantic versioning (SemVer):
|
|
|
235
235
|
|
|
236
236
|
Examples:
|
|
237
237
|
- `0.1.7` → `0.1.8` (patch release)
|
|
238
|
-
- `0.1.8` → `0.2.
|
|
239
|
-
- `0.2.
|
|
238
|
+
- `0.1.8` → `0.2.2` (minor release)
|
|
239
|
+
- `0.2.2` → `1.0.0` (major release)
|
|
240
240
|
|
|
241
241
|
### Pre-releases
|
|
242
242
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: tlpytools
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.2
|
|
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
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "tlpytools"
|
|
7
|
-
version = "0.2.
|
|
7
|
+
version = "0.2.2"
|
|
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"
|
|
@@ -120,10 +120,8 @@ class OrcaLogger:
|
|
|
120
120
|
|
|
121
121
|
def _setup_logger(self):
|
|
122
122
|
"""Set up the logger with consistent formatting and handlers."""
|
|
123
|
-
#
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
logger_name = f"orca_{uuid.uuid4().hex[:8]}"
|
|
123
|
+
# Determine logger name from git tag, git SHA, or random session ID
|
|
124
|
+
logger_name = self._resolve_logger_name()
|
|
127
125
|
|
|
128
126
|
# Create logger
|
|
129
127
|
self._logger = logging.getLogger(logger_name)
|
|
@@ -172,6 +170,53 @@ class OrcaLogger:
|
|
|
172
170
|
|
|
173
171
|
self._logger.info("=" * 80)
|
|
174
172
|
|
|
173
|
+
def _resolve_logger_name(self) -> str:
|
|
174
|
+
"""
|
|
175
|
+
Resolve a stable logger name using git metadata when available.
|
|
176
|
+
|
|
177
|
+
Priority:
|
|
178
|
+
1. Git tag pointing at HEAD -> f"orca_{tag}"
|
|
179
|
+
2. Git SHA (first 7 chars) -> f"orca_{sha}"
|
|
180
|
+
3. Random session UUID -> f"session_{uuid8}"
|
|
181
|
+
"""
|
|
182
|
+
project_cwd = os.getcwd()
|
|
183
|
+
try:
|
|
184
|
+
# Priority 1: git tag pointing exactly at HEAD
|
|
185
|
+
tag_result = subprocess.run(
|
|
186
|
+
["git", "describe", "--tags", "--exact-match", "HEAD"],
|
|
187
|
+
capture_output=True,
|
|
188
|
+
text=True,
|
|
189
|
+
timeout=5,
|
|
190
|
+
cwd=project_cwd,
|
|
191
|
+
)
|
|
192
|
+
if tag_result.returncode == 0:
|
|
193
|
+
git_version = tag_result.stdout.strip()
|
|
194
|
+
if git_version:
|
|
195
|
+
return f"orca_{git_version}"
|
|
196
|
+
except Exception:
|
|
197
|
+
pass
|
|
198
|
+
|
|
199
|
+
try:
|
|
200
|
+
# Priority 2: short git SHA (7 characters)
|
|
201
|
+
sha_result = subprocess.run(
|
|
202
|
+
["git", "rev-parse", "--short=7", "HEAD"],
|
|
203
|
+
capture_output=True,
|
|
204
|
+
text=True,
|
|
205
|
+
timeout=5,
|
|
206
|
+
cwd=project_cwd,
|
|
207
|
+
)
|
|
208
|
+
if sha_result.returncode == 0:
|
|
209
|
+
git_sha = sha_result.stdout.strip()
|
|
210
|
+
if git_sha:
|
|
211
|
+
return f"orca_{git_sha}"
|
|
212
|
+
except Exception:
|
|
213
|
+
pass
|
|
214
|
+
|
|
215
|
+
# Priority 3: random session UUID fallback
|
|
216
|
+
import uuid
|
|
217
|
+
|
|
218
|
+
return f"session_{uuid.uuid4().hex[:8]}"
|
|
219
|
+
|
|
175
220
|
def _log_system_info(self):
|
|
176
221
|
"""
|
|
177
222
|
Log detailed system information.
|
|
@@ -3692,16 +3737,15 @@ class OrcaOrchestrator:
|
|
|
3692
3737
|
|
|
3693
3738
|
# Create a platform-specific command to set the PYTHONPATH
|
|
3694
3739
|
# Use step_directory instead of os.getcwd() for consistency
|
|
3740
|
+
# PYTHONHOME and PYTHONPATH are cleared first to prevent the parent
|
|
3741
|
+
# Python process (e.g. Jupyter/tlpytools env) from leaking its
|
|
3742
|
+
# library paths into the component subprocess
|
|
3695
3743
|
if os.name == "nt": # Windows
|
|
3696
3744
|
# On Windows, use SET command
|
|
3697
|
-
pythonpath_cmd =
|
|
3698
|
-
f"set PYTHONPATH={ORCA_DIR};{step_directory};%PYTHONPATH% && "
|
|
3699
|
-
)
|
|
3745
|
+
pythonpath_cmd = f"set PYTHONHOME= && set PYTHONPATH={ORCA_DIR};{step_directory} && "
|
|
3700
3746
|
else: # Unix/Linux/Mac
|
|
3701
3747
|
# On Unix-like systems, use export command
|
|
3702
|
-
pythonpath_cmd =
|
|
3703
|
-
f"export PYTHONPATH={ORCA_DIR}:{step_directory}:$PYTHONPATH && "
|
|
3704
|
-
)
|
|
3748
|
+
pythonpath_cmd = f"unset PYTHONHOME && export PYTHONPATH={ORCA_DIR}:{step_directory} && "
|
|
3705
3749
|
|
|
3706
3750
|
# Modify the command to ensure environment can be found
|
|
3707
3751
|
modified_command = f"{pythonpath_cmd}{command}"
|
|
@@ -6224,8 +6268,8 @@ class OrcaOrchestrator:
|
|
|
6224
6268
|
# Reload configuration to pick up any YAML changes
|
|
6225
6269
|
self.reload_configuration()
|
|
6226
6270
|
|
|
6227
|
-
# Update status
|
|
6228
|
-
self.state.update(status="running")
|
|
6271
|
+
# Update status and clear any stale error from a previous failed run
|
|
6272
|
+
self.state.update(status="running", error=None)
|
|
6229
6273
|
|
|
6230
6274
|
# Add safety counter to prevent infinite loops
|
|
6231
6275
|
max_steps = self.state.get("total_iterations", 1) * len(
|
|
@@ -6289,8 +6333,8 @@ class OrcaOrchestrator:
|
|
|
6289
6333
|
self.logger.error("Error executing step: %s", step_name)
|
|
6290
6334
|
return False
|
|
6291
6335
|
|
|
6292
|
-
# Update state to reflect completion
|
|
6293
|
-
self.state.update(status="completed")
|
|
6336
|
+
# Update state to reflect completion and clear any previously recorded error
|
|
6337
|
+
self.state.update(status="completed", error=None)
|
|
6294
6338
|
self.logger.info("Model run completed successfully")
|
|
6295
6339
|
return True
|
|
6296
6340
|
|
|
@@ -6311,8 +6355,8 @@ class OrcaOrchestrator:
|
|
|
6311
6355
|
# Reload configuration to pick up any YAML changes
|
|
6312
6356
|
self.reload_configuration()
|
|
6313
6357
|
|
|
6314
|
-
# Update status
|
|
6315
|
-
self.state.update(status="running")
|
|
6358
|
+
# Update status and clear any stale error from a previous failed run
|
|
6359
|
+
self.state.update(status="running", error=None)
|
|
6316
6360
|
|
|
6317
6361
|
# Add safety counter to prevent infinite loops
|
|
6318
6362
|
max_steps = self.state.get("total_iterations", 1) * len(
|
|
@@ -6392,8 +6436,8 @@ class OrcaOrchestrator:
|
|
|
6392
6436
|
|
|
6393
6437
|
return False
|
|
6394
6438
|
|
|
6395
|
-
# Update state to reflect completion
|
|
6396
|
-
self.state.update(status="completed")
|
|
6439
|
+
# Update state to reflect completion and clear any previously recorded error
|
|
6440
|
+
self.state.update(status="completed", error=None)
|
|
6397
6441
|
|
|
6398
6442
|
# Final sync to cloud after completion
|
|
6399
6443
|
self.logger.info("Final state sync to cloud after model completion")
|
|
@@ -6450,12 +6494,12 @@ class OrcaOrchestrator:
|
|
|
6450
6494
|
current_iter,
|
|
6451
6495
|
max_iteration,
|
|
6452
6496
|
)
|
|
6453
|
-
self.state.update(status="completed")
|
|
6497
|
+
self.state.update(status="completed", error=None)
|
|
6454
6498
|
return True
|
|
6455
6499
|
|
|
6456
|
-
# Update status to running if not already
|
|
6500
|
+
# Update status to running if not already, clearing any stale error
|
|
6457
6501
|
if self.state.get("status") != "running":
|
|
6458
|
-
self.state.update(status="running")
|
|
6502
|
+
self.state.update(status="running", error=None)
|
|
6459
6503
|
|
|
6460
6504
|
# Get the next step to execute
|
|
6461
6505
|
step_name = self.state.get_next_step()
|
|
@@ -6472,7 +6516,7 @@ class OrcaOrchestrator:
|
|
|
6472
6516
|
# Check if we've exceeded the total iterations
|
|
6473
6517
|
if self.state.is_all_iterations_complete():
|
|
6474
6518
|
self.logger.info("All iterations completed")
|
|
6475
|
-
self.state.update(status="completed")
|
|
6519
|
+
self.state.update(status="completed", error=None)
|
|
6476
6520
|
return True
|
|
6477
6521
|
|
|
6478
6522
|
# Get the first step of the new iteration
|
|
@@ -6507,7 +6551,7 @@ class OrcaOrchestrator:
|
|
|
6507
6551
|
|
|
6508
6552
|
# Check if we just completed the last iteration
|
|
6509
6553
|
if self.state.is_all_iterations_complete():
|
|
6510
|
-
self.state.update(status="completed")
|
|
6554
|
+
self.state.update(status="completed", error=None)
|
|
6511
6555
|
self.logger.info("Model run completed successfully")
|
|
6512
6556
|
|
|
6513
6557
|
self.logger.info("Step '%s' completed successfully", step_name)
|
|
@@ -6552,12 +6596,12 @@ class OrcaOrchestrator:
|
|
|
6552
6596
|
current_iter,
|
|
6553
6597
|
max_iteration,
|
|
6554
6598
|
)
|
|
6555
|
-
self.state.update(status="completed")
|
|
6599
|
+
self.state.update(status="completed", error=None)
|
|
6556
6600
|
return True
|
|
6557
6601
|
|
|
6558
|
-
# Update status to running if not already
|
|
6602
|
+
# Update status to running if not already, clearing any stale error
|
|
6559
6603
|
if self.state.get("status") != "running":
|
|
6560
|
-
self.state.update(status="running")
|
|
6604
|
+
self.state.update(status="running", error=None)
|
|
6561
6605
|
|
|
6562
6606
|
# Remember the starting iteration
|
|
6563
6607
|
starting_iter = self.state.get_display_iteration()
|
|
@@ -6579,7 +6623,7 @@ class OrcaOrchestrator:
|
|
|
6579
6623
|
|
|
6580
6624
|
# Check if we've completed all iterations
|
|
6581
6625
|
if self.state.is_all_iterations_complete():
|
|
6582
|
-
self.state.update(status="completed")
|
|
6626
|
+
self.state.update(status="completed", error=None)
|
|
6583
6627
|
self.logger.info("All iterations completed")
|
|
6584
6628
|
|
|
6585
6629
|
return 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
|