Skip to content

Commit c1b33f4

Browse files
midgemacfMacFarland, Midgie
andauthored
Release 1.0.3
Primarily a fix for bugs introduced by ty type checking changes: - Moved where the sqlalchemy session typing is checked - changed type_ -> type in load_data check --------- Co-authored-by: MacFarland, Midgie <macfarlandmj@ornl.gov>
1 parent 897b498 commit c1b33f4

6 files changed

Lines changed: 45 additions & 31 deletions

File tree

CHANGELOG.md

Lines changed: 22 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -38,10 +38,28 @@ This project adheres to [Semantic Versioning](https://semver.org/).
3838
3939
-->
4040

41-
## [1.0.0] - 2025-05-09
42-
- Initial commit
41+
## [Unreleased] - YYYY-MM-DD
42+
### Added
43+
- 🔥 Environment variable OPENSAMPL_COMPOSE_FILE used to identify compose file used for opensampl-server
44+
45+
### Changed
46+
- ⚡ Order of changelog, newest on top
47+
48+
### Fixed
49+
- 🩹 Bugs in load_data introduced by ty type checking changes
4350

4451

52+
## [1.0.2] - 2025-05-12
53+
### Added
54+
- 🔥 `black` added as a dependency for auto-creation of probe types
55+
- 🔥 `ty` added as a dependency for type-checking
56+
57+
### Fixed
58+
- 🩹 `ty` type checking errors addressed
59+
60+
### Changed
61+
- ⚡ linting github action now confirms that the documentation can be built
62+
4563
## [1.0.1] - 2025-05-09
4664
### Added
4765
- 🔥 pytest as a dev dependency, used for running tests
@@ -63,13 +81,5 @@ This project adheres to [Semantic Versioning](https://semver.org/).
6381
- 🗡️ Remove unused imports from many files
6482
- 🗡️ Remove commented-out code in some classes
6583

66-
## [1.0.2] - 2025-05-12
67-
### Added
68-
- 🔥 `black` added as a dependency for auto-creation of probe types
69-
- 🔥 `ty` added as a dependency for type-checking
70-
71-
### Fixed
72-
- 🩹 `ty` type checking errors addressed
73-
74-
### Changed
75-
- ⚡ linting github action now confirms that the documentation can be built
84+
## [1.0.0] - 2025-05-09
85+
- Initial commit

opensampl/db/orm.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ def __init__(self, **kwargs: dict):
5656
lat = kwargs.pop("lat")
5757
lon = kwargs.pop("lon")
5858
z = kwargs.pop("z", None)
59-
projection = kwargs.pop("projection", 4326)
59+
projection = int(kwargs.pop("projection", 4326))
6060
point_str = f"POINT({lon} {lat} {z})" if z is not None else f"POINT({lon} {lat})"
6161
kwargs["geom"] = WKTElement(point_str, srid=projection)
6262
super().__init__(**kwargs)

opensampl/helpers/source_writer.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,11 @@ def _get_statement_type(self, stmt: cst.CSTNode) -> str:
1515
if isinstance(stmt, cst.SimpleStatementLine): # noqa: SIM102
1616
if len(stmt.body) == 1: # noqa: SIM102
1717
if isinstance(stmt.body[0], cst.Assign):
18-
if isinstance(stmt.body[0].targets[0], cst.Name):
19-
name = stmt.body[0].targets[0].value
18+
if isinstance(stmt.body[0].targets[0], cst.Name): # ty: ignore[unresolved-attribute]
19+
name = stmt.body[0].targets[0].value # ty: ignore[unresolved-attribute]
2020
if name.startswith("__"):
2121
return "dunder"
22-
value = stmt.body[0].value
22+
value = stmt.body[0].value # ty: ignore[unresolved-attribute]
2323
if isinstance(value, cst.Call):
2424
func_name = str(value.func.value)
2525
if "Column" in func_name:

opensampl/load_data.py

Lines changed: 17 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -117,14 +117,15 @@ def write_to_table(
117117
SQLAlchemyError: For database errors
118118
119119
"""
120-
if not isinstance(session, Session):
121-
raise TypeError("Session must be a SQLAlchemy session")
122120
if if_exists not in ["error", "replace", "update", "ignore"]:
123121
raise ValueError("on_conflict must be one of: 'error', 'replace', 'update', 'ignore'")
124122

125123
if ENV_VARS.ROUTE_TO_BACKEND.get_value():
126124
return {"table": table, "data": data, "if_exists": if_exists}
127125

126+
if not isinstance(session, Session):
127+
raise TypeError("Session must be a SQLAlchemy session")
128+
128129
try:
129130
TableModel = resolve_table_model(table) # noqa: N806
130131
inspector = inspect(TableModel)
@@ -201,7 +202,7 @@ def build_pk_conditions(
201202
pk_conditions.append(getattr(TableModel, pk) == data[pk])
202203
else:
203204
logger.debug(f"{pk} is primary but not in data")
204-
logger.debug(f"{pk_conditions=}")
205+
logger.debug(f"pk_conditions={', '.join([str(x) for x in pk_conditions])}")
205206
return pk_conditions
206207

207208

@@ -225,7 +226,7 @@ def extract_unique_constraints(inspector: Any, data: dict[str, Any]):
225226
cols = [col.key for col in constraint.columns]
226227
if all(col in data for col in cols):
227228
unique_constraints.append([(col, data[col]) for col in cols])
228-
logger.debug(f"{unique_constraints=}")
229+
logger.debug(f"unique_constraints={', '.join([str(x) for x in unique_constraints])}")
229230
return unique_constraints
230231

231232

@@ -327,8 +328,6 @@ def handle_existing_entry( # noqa: PLR0913
327328
@route_or_direct("load_time_data", send_file=True)
328329
def load_time_data(probe_key: ProbeKey, data: pd.DataFrame, session: Optional[Session] = None):
329330
"""Load time series data"""
330-
if not isinstance(session, Session):
331-
raise TypeError("Session must be a SQLAlchemy session")
332331
route_to_backend = ENV_VARS.ROUTE_TO_BACKEND.get_value()
333332
if route_to_backend:
334333
csv_data = data.to_csv(index=False).encode("utf-8")
@@ -339,6 +338,8 @@ def load_time_data(probe_key: ProbeKey, data: pd.DataFrame, session: Optional[Se
339338

340339
from opensampl.db.orm import ProbeData, ProbeMetadata
341340

341+
if not isinstance(session, Session):
342+
raise TypeError("Session must be a SQLAlchemy session")
342343
try:
343344
# Verify probe exists and get UUID
344345
probe = (
@@ -357,9 +358,10 @@ def load_time_data(probe_key: ProbeKey, data: pd.DataFrame, session: Optional[Se
357358
df["probe_uuid"] = probe.uuid
358359

359360
# Ensure correct dtypes
360-
df = df.astype({"time": "datetime64[ns]", "value": "float64", "probe_uuid": str})
361+
df["time"] = pd.to_datetime(df["time"], utc=True, errors="raise")
362+
df = df.astype({"value": "float64", "probe_uuid": str})
361363

362-
dtype = {column.name: column.type_ for column in ProbeData.__table__.columns}
364+
dtype = {column.name: column.type for column in ProbeData.__table__.columns}
363365

364366
# Write directly to database using pandas
365367
df.to_sql(
@@ -387,8 +389,6 @@ def load_probe_metadata(
387389
session: Optional[Session] = None,
388390
):
389391
"""Write object to table"""
390-
if not isinstance(session, Session):
391-
raise TypeError("Session must be a SQLAlchemy session")
392392
route_to_backend = ENV_VARS.ROUTE_TO_BACKEND.get_value()
393393
if route_to_backend:
394394
return {
@@ -397,6 +397,9 @@ def load_probe_metadata(
397397
"data": data,
398398
}
399399

400+
if not isinstance(session, Session):
401+
raise TypeError("Session must be a SQLAlchemy session")
402+
400403
try:
401404
from opensampl.db.orm import ProbeMetadata
402405

@@ -428,11 +431,13 @@ def load_probe_metadata(
428431
@route_or_direct("create_new_tables", method="GET")
429432
def create_new_tables(create_schema: bool = True, session: Optional[Session] = None):
430433
"""Use the ORM definition to create all tables, optionally creating the schema as well"""
431-
if not isinstance(session, Session):
432-
raise TypeError("Session must be a SQLAlchemy session")
433434
route_to_backend = ENV_VARS.ROUTE_TO_BACKEND.get_value()
434435
if route_to_backend:
435436
return {"create_schema": create_schema}
437+
438+
if not isinstance(session, Session):
439+
raise TypeError("Session must be a SQLAlchemy session")
440+
436441
try:
437442
if create_schema:
438443
session.execute(text(f"CREATE SCHEMA IF NOT EXISTS {Base.metadata.schema}"))

opensampl/server/cli.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ def get_compose_command():
4848
def get_cast_compose_file():
4949
"""Get the fully qualified path to the docker-compose.yaml file included inside the package."""
5050
try:
51-
filename = "docker-compose.yaml"
51+
filename = os.getenv("OPENSAMPL_COMPOSE_FILE", "docker-compose.yaml")
5252
with pkg_resources.path("opensampl.server", filename) as path:
5353
return str(path)
5454
except ImportError:

pyproject.toml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[project]
22
name = "opensampl"
3-
version = "1.0.2"
3+
version = "1.0.3"
44
description = "Python tools for adding clock data to a timescale db."
55
authors = [
66
{ name = "Midgie MacFarland", email = "macfarlandmj@ornl.gov" },
@@ -96,4 +96,3 @@ quote-style = "double"
9696
indent-style = "space"
9797
skip-magic-trailing-comma = false
9898
docstring-code-format = true
99-

0 commit comments

Comments
 (0)