Skip to content

Add type hints and checks#183

Merged
wuan merged 11 commits intomainfrom
add_types_new
Apr 22, 2026
Merged

Add type hints and checks#183
wuan merged 11 commits intomainfrom
add_types_new

Conversation

@wuan
Copy link
Copy Markdown
Owner

@wuan wuan commented Apr 22, 2026

No description provided.

wuan and others added 5 commits April 20, 2026 20:29
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR introduces static typing support (mypy) and incrementally adds type hints / minor refactors across the blitzortung package and tests to improve type safety and lintability.

Changes:

  • Add mypy as a dev dependency, a mypy.ini configuration, and a pre-commit mypy hook.
  • Add/adjust type annotations across core modules (data, geom, util, db/service layers) and fix a few builder behaviors.
  • Clean up various test imports/fixtures to align with the updated code and lint rules.

Reviewed changes

Copilot reviewed 38 out of 39 changed files in this pull request and generated 7 comments.

Show a summary per file
File Description
tests/test_dataimport.py Remove unused call import.
tests/test_config.py Remove legacy Python 2 configparser branching in tests.
tests/service/test_strikes.py Remove redundant time_interval import (fixture still provided via conftest).
tests/service/test_strike_grid.py Remove redundant time_interval import (fixture still provided via conftest).
tests/service/test_metrics.py Reorder imports for clarity.
tests/db/test_db_table.py Remove unused pytest import.
tests/db/test_db_query_builder.py Remove unused shapely import.
tests/db/test_db.py Remove unused imports from DB tests.
tests/conftest.py Adjust import ordering.
tests/builder/test_builder_base.py Add fixture and update tests to use builders with initialized timestamps.
pyproject.toml Add mypy to dev dependencies.
poetry.lock Update lockfile (Poetry version + mypy and deps).
mypy.ini Add mypy configuration, ignoring tests and some missing imports.
blitzortung/websocket.py Add typing imports/annotations in websocket decode helper.
blitzortung/util.py Add annotations, modernize typing, and add a few type ignores for mixed datetime/Timestamp ops.
blitzortung/service/strike.py Remove unused create_time_interval import.
blitzortung/service/metrics.py Add return/arg annotations.
blitzortung/service/db.py Add type annotation for Deferred returned by pool start.
blitzortung/service/init.py Add typed injector getters (but with formatting issues).
blitzortung/geom.py Add annotations and some runtime type checks in geometry helpers.
blitzortung/db/table.py Reorder imports / add explicit psycopg2 imports.
blitzortung/db/query_builder.py Add annotation to local query variable (formatting issues).
blitzortung/db/query.py Type columns and ensure it’s a list (formatting issues).
blitzortung/db/mapper.py Remove unused shapely import.
blitzortung/db/init.py Reorder imports and simplify return.
blitzortung/data.py Add extensive typing and refactor Timestamp/Event/GridData logic.
blitzortung/config.py Add annotations and explicit None return in config search.
blitzortung/cli/webservice_insertlog.py Import ordering + add typing; adjust UA version parsing (introduces a bug).
blitzortung/cli/webservice.py Add typing, tweak reactor import pattern, and add a few type ignores/guards.
blitzortung/cli/update.py Import ordering change.
blitzortung/cli/imprt_websocket.py Import ordering and remove obsolete thread import fallback.
blitzortung/cli/imprt.py Import ordering change.
blitzortung/cli/db.py Add mypy ignore for optional end_time assignment.
blitzortung/cache.py Make last_cleanup a float.
blitzortung/builder/strike.py Preserve exception context and require timestamp before build.
blitzortung/builder/base.py Require timestamp before build.
blitzortung/base.py Add annotations and adjust equality/point construction behavior.
blitzortung/init.py Reorder declarations for typing/linting.
.pre-commit-config.yaml Bump hook versions and add mypy pre-commit hook.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +28 to 32
import blitzortung

return INJECTOR.get(strike.StrikeQuery)
result : StrikeQuery = blitzortung.INJECTOR.get(strike.StrikeQuery)
return result

Copy link

Copilot AI Apr 22, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These annotations use non-PEP8 spacing (e.g., result : StrikeQuery and double spaces), which is likely to trigger pylint's whitespace checks in the pre-commit hook. Use result: StrikeQuery = ... with consistent spacing.

Copilot uses AI. Check for mistakes.
Comment thread blitzortung/config.py Outdated
Comment thread blitzortung/db/query.py Outdated
Comment thread blitzortung/db/query_builder.py Outdated
Comment thread blitzortung/websocket.py
Comment thread blitzortung/data.py Outdated
Comment thread blitzortung/cli/webservice_insertlog.py Outdated
wuan and others added 3 commits April 22, 2026 12:16
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- Fix PEP8 whitespace in type annotations (result : T -> result: T)
- Guard Timestamp.value against None datetime
- Make user agent version parsing conditional on 'bo-android' prefix

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 39 out of 40 changed files in this pull request and generated 8 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread blitzortung/data.py
Comment on lines +153 to 157
def __lt__(self, other: object) -> bool:
if isinstance(other, dt_module.datetime):
return self.datetime < other
else:
elif isinstance(other, Timestamp):
return self.datetime < other.datetime or (
Copy link

Copilot AI Apr 22, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In Timestamp.__lt__, the fallback for unsupported types is return False (and the other comparison operators follow the same pattern). For rich comparisons, returning NotImplemented is preferable so Python can fall back to the other operand or raise TypeError; returning False can silently mask bugs (e.g., Timestamp() < 5 becomes False). Consider returning NotImplemented for the unsupported-type branch and widening the return annotation accordingly.

Copilot uses AI. Check for mistakes.
Comment thread blitzortung/base.py
Comment on lines +30 to +33
def __eq__(self, other: object) -> bool:
if isinstance(other, self.__class__):
return self.__dict__ == other.__dict__
return NotImplemented
return False
Copy link

Copilot AI Apr 22, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

EqualityAndHash.__eq__ now returns False for unsupported types rather than NotImplemented (and __ne__ similarly returns True). Returning NotImplemented is the standard pattern for rich comparisons with unsupported operand types; it avoids surprising asymmetric behavior and lets Python fall back to the reflected operation.

Copilot uses AI. Check for mistakes.
Comment thread tests/test_config.py
import configparser
except ImportError:
import ConfigParser as configparser
config_parser_module = "configparser"
Copy link

Copilot AI Apr 22, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

config_parser_module is no longer referenced in this test file after removing the Python 2/3 import logic, so this assignment is now dead code. Consider deleting it (and any related now-unused imports like sys) to keep the test module minimal.

Copilot uses AI. Check for mistakes.
Comment on lines +44 to +52
result : GlobalStrikeGridQuery = blitzortung.INJECTOR.get(strike_grid.GlobalStrikeGridQuery)
return result


def histogram_query() -> HistogramQuery:
from .. import INJECTOR
import blitzortung

return INJECTOR.get(histogram.HistogramQuery)
result : HistogramQuery = blitzortung.INJECTOR.get(histogram.HistogramQuery)
return result
Copy link

Copilot AI Apr 22, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are a few PEP 8 formatting issues here (e.g., result : and extra spaces around =). These will likely be flagged by linters/formatters and make the typed assignments harder to read; use result: Type = ... with single spaces.

Copilot uses AI. Check for mistakes.
Comment thread blitzortung/cli/webservice.py Outdated
user_agent_parts = user_agent.split(' ')[0].rsplit('-', 1)
version_string = user_agent_parts[1] if len(user_agent_parts) > 1 else None
user_agent_version = int(version_string) if user_agent_parts[0] == 'bo-android' else 0
user_agent_version = int(version_string) if user_agent_parts[0] == 'bo-android' and version_string is not None else 0
Copy link

Copilot AI Apr 22, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

parse_user_agent can still raise ValueError when the version suffix is non-numeric (e.g., bo-android-abc), because int(version_string) is not guarded. Mirror the defensive parsing used in fix_bad_accept_header (try/except and default to 0) so malformed user agents don't crash the request handler.

Suggested change
user_agent_version = int(version_string) if user_agent_parts[0] == 'bo-android' and version_string is not None else 0
if user_agent_parts[0] == 'bo-android' and version_string is not None:
try:
user_agent_version = int(version_string)
except ValueError:
user_agent_version = 0
else:
user_agent_version = 0

Copilot uses AI. Check for mistakes.
Comment thread test.py Outdated
Comment on lines +3 to +7
import blitzortung.config

if __name__ == "__main__":
print("yes")

Copy link

Copilot AI Apr 22, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks like a leftover local sanity-check script (it only imports blitzortung.config and prints "yes"). Shipping it at the repo root can confuse tooling (test discovery, packaging, linting); consider removing it or moving it under an examples/ or scripts/ directory with a more specific name/purpose.

Suggested change
import blitzortung.config
if __name__ == "__main__":
print("yes")
"""Minimal utility for verifying that ``blitzortung.config`` is importable."""
import importlib
def main() -> int:
"""Import the configuration module and exit successfully if it is available."""
importlib.import_module("blitzortung.config")
return 0
if __name__ == "__main__":
raise SystemExit(main())

Copilot uses AI. Check for mistakes.
Comment thread .pre-commit-config.yaml Outdated
hooks:
- id: mypy
files: ^blitzortung/
additional_dependencies: [pyproj, shapely, psycopg2, fasteners, txpostgres]
Copy link

Copilot AI Apr 22, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The mypy pre-commit hook installs psycopg2 into an isolated environment; this often requires native build dependencies (libpq headers) and can fail on contributor machines/CI runners. Consider switching the hook dependency to psycopg2-binary (or documenting/installing the required system packages) to make pre-commit setup reliable.

Suggested change
additional_dependencies: [pyproj, shapely, psycopg2, fasteners, txpostgres]
additional_dependencies: [pyproj, shapely, psycopg2-binary, fasteners, txpostgres]

Copilot uses AI. Check for mistakes.
Comment thread blitzortung/data.py Outdated
Comment on lines +37 to +39
_datetime: dt_module.datetime
nanosecond: int

Copy link

Copilot AI Apr 22, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Timestamp can be constructed as Timestamp(None) (see NaT), and __init__ assigns dt = None in that case, but _datetime is annotated as non-optional datetime. To keep the type hints sound, _datetime (and the datetime property) should be typed as datetime | None (and any accessors should handle the None case).

Copilot uses AI. Check for mistakes.
wuan and others added 3 commits April 22, 2026 13:32
- Return NotImplemented in rich comparisons for unsupported types
- Fix parse_user_agent ValueError with try/except around int()
- Type Timestamp._datetime as datetime | None
- Switch mypy pre-commit to psycopg2-binary
- Remove leftover test.py from repo root

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
PyPy gc.get_stats takes a boolean, CPython takes no args.
Separate branches so type checkers can reason about each call correctly.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@sonarqubecloud
Copy link
Copy Markdown

Quality Gate Failed Quality Gate failed

Failed conditions
E Reliability Rating on New Code (required ≥ A)

See analysis details on SonarQube Cloud

Catch issues before they fail your Quality Gate with our IDE extension SonarQube for IDE

@wuan wuan marked this pull request as ready for review April 22, 2026 13:52
@wuan wuan merged commit 553eb1c into main Apr 22, 2026
8 of 9 checks passed
@wuan wuan deleted the add_types_new branch April 22, 2026 18:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants