Skip to content

Commit 66b71be

Browse files
committed
Merge commit '61078c7198b46c4d4ff336caa7678bd814b6fa82' into patch-595
2 parents b0ba7ea + 61078c7 commit 66b71be

File tree

9 files changed

+130
-11
lines changed

9 files changed

+130
-11
lines changed

.github/workflows/core_tests.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,7 @@ jobs:
130130
131131
- run: uv run pytest test/test_skim_name_conflicts.py
132132
- run: uv run pytest test/random_seed/test_random_seed.py
133+
- run: uv run pytest test/trace_id/test_trace_id.py
133134

134135
builtin_regional_models:
135136
needs: foundation

activitysim/cli/run.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,14 @@
99
import sys
1010
import warnings
1111
from datetime import datetime
12+
import struct
13+
import time
1214

1315
import numpy as np
1416

1517
from activitysim.core import chunk, config, mem, timing, tracing, workflow
1618
from activitysim.core.configuration import FileSystem, Settings
19+
from activitysim.core.run_id import RunId
1720

1821
from activitysim.abm.models.settings_checker import check_model_settings
1922

@@ -29,6 +32,7 @@
2932
"settings_file_name",
3033
"imported_extensions",
3134
"run_timestamp",
35+
"run_id",
3236
]
3337

3438

@@ -161,6 +165,8 @@ def inject_arg(name, value):
161165
# 'configs', 'data', and 'output' folders by default
162166
os.chdir(args.working_dir)
163167

168+
inject_arg("run_id", state.tracing.run_id)
169+
164170
if args.ext:
165171
for e in args.ext:
166172
basepath, extpath = os.path.split(e)
@@ -268,6 +274,7 @@ def run(args):
268274
"""
269275

270276
state = workflow.State()
277+
_init_run_id = state.tracing.run_id
271278

272279
# register abm steps and other abm-specific injectables
273280
# by default, assume we are running activitysim.abm

activitysim/core/configuration/top.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
from pathlib import Path
44
from typing import Any, Literal
5+
import struct
6+
import time
57

68
from pydantic import model_validator, validator
79

activitysim/core/mp_tasks.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919

2020
from activitysim.core import config, mem, tracing, util, workflow
2121
from activitysim.core.configuration import FileSystem, Settings
22+
from activitysim.core.run_id import RunId
2223
from activitysim.core.workflow.checkpoint import (
2324
CHECKPOINT_NAME,
2425
CHECKPOINT_TABLE_NAME,
@@ -890,6 +891,10 @@ def setup_injectables_and_logging(injectables, locutor: bool = True) -> workflow
890891
injects injectables
891892
"""
892893
state = workflow.State()
894+
_run_id = injectables.get("run_id", None)
895+
if _run_id:
896+
state.tracing.run_id = RunId(_run_id)
897+
893898
state = state.initialize_filesystem(**injectables)
894899
state.settings = injectables.get("settings", Settings())
895900
state.filesystem.parse_settings(state.settings)

activitysim/core/run_id.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import struct
2+
import time
3+
4+
5+
class RunId(str):
6+
def __new__(cls, x=None):
7+
if x is None:
8+
return cls(
9+
hex(struct.unpack("<Q", struct.pack("<d", time.time()))[0])[-6:].lower()
10+
)
11+
return super().__new__(cls, x)

activitysim/core/workflow/tracing.py

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,9 @@
55
import logging
66
import logging.config
77
import os
8-
import struct
98
import sys
109
import tarfile
1110
import tempfile
12-
import time
1311
from collections.abc import Mapping, MutableMapping, Sequence
1412
from pathlib import Path
1513
from typing import Any, Optional
@@ -22,6 +20,7 @@
2220
from activitysim.core.test import assert_equal, assert_frame_substantively_equal
2321
from activitysim.core.workflow.accessor import FromState, StateAccessor
2422
from activitysim.core.exceptions import TableSlicingError
23+
from activitysim.core.run_id import RunId
2524

2625
logger = logging.getLogger(__name__)
2726

@@ -37,15 +36,6 @@
3736
]
3837

3938

40-
class RunId(str):
41-
def __new__(cls, x=None):
42-
if x is None:
43-
return cls(
44-
hex(struct.unpack("<Q", struct.pack("<d", time.time()))[0])[-6:].lower()
45-
)
46-
return super().__new__(cls, x)
47-
48-
4939
class Tracing(StateAccessor):
5040
"""
5141
Methods to provide the tracing capabilities of ActivitySim.

test/trace_id/.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
configs*/
2+
output/

test/trace_id/simulation.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# ActivitySim
2+
# See full license in LICENSE.txt.
3+
4+
from __future__ import annotations
5+
6+
import argparse
7+
import sys
8+
9+
from activitysim.cli.run import add_run_args, run
10+
11+
if __name__ == "__main__":
12+
parser = argparse.ArgumentParser()
13+
add_run_args(parser)
14+
args = parser.parse_args()
15+
16+
sys.exit(run(args))

test/trace_id/test_trace_id.py

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
from __future__ import annotations
2+
3+
# ActivitySim
4+
# See full license in LICENSE.txt.
5+
import importlib.resources
6+
import os
7+
import subprocess
8+
from shutil import copytree
9+
10+
import pandas as pd
11+
import pandas.testing as pdt
12+
import yaml
13+
14+
15+
def update_settings(settings_file, key, value):
16+
with open(settings_file, "r") as f:
17+
settings = yaml.safe_load(f)
18+
f.close()
19+
20+
settings[key] = value
21+
22+
with open(settings_file, "w") as f:
23+
yaml.safe_dump(settings, f)
24+
f.close()
25+
26+
27+
def test_trace_ids_have_same_hash():
28+
def example_path(dirname):
29+
resource = os.path.join("examples", "prototype_mtc", dirname)
30+
return str(importlib.resources.files("activitysim").joinpath(resource))
31+
32+
def test_path(dirname):
33+
return os.path.join(os.path.dirname(__file__), dirname)
34+
35+
new_configs_dir = test_path("configs")
36+
new_mp_configs_dir = test_path("configs_mp")
37+
new_settings_file = os.path.join(new_configs_dir, "settings.yaml")
38+
copytree(example_path("configs"), new_configs_dir)
39+
copytree(example_path("configs_mp"), new_mp_configs_dir)
40+
41+
update_settings(
42+
new_settings_file, "trace_hh_id", 1932009
43+
) # Household in the prototype_mtc example with 11 people
44+
45+
def check_csv_suffix(directory):
46+
suffix = None
47+
mismatched_files = []
48+
for root, dirs, files in os.walk(directory):
49+
for filename in files:
50+
if filename.lower().endswith(".csv"):
51+
file_suffix = filename[-10:]
52+
if suffix is None:
53+
suffix = file_suffix
54+
elif file_suffix != suffix:
55+
mismatched_files.append(os.path.join(root, filename))
56+
if mismatched_files:
57+
raise AssertionError(
58+
f"CSV files with mismatched suffixes: {mismatched_files}"
59+
)
60+
61+
file_path = os.path.join(os.path.dirname(__file__), "simulation.py")
62+
63+
run_args = [
64+
"-c",
65+
test_path("configs_mp"),
66+
"-c",
67+
test_path("configs"),
68+
"-d",
69+
example_path("data"),
70+
"-o",
71+
test_path("output"),
72+
]
73+
74+
try:
75+
os.mkdir(test_path("output"))
76+
except FileExistsError:
77+
pass
78+
79+
subprocess.run(["coverage", "run", "-a", file_path] + run_args, check=True)
80+
81+
check_csv_suffix(os.path.join(test_path("output"), "trace"))
82+
83+
84+
if __name__ == "__main__":
85+
test_trace_ids_have_same_hash()

0 commit comments

Comments
 (0)