mirror of
https://github.com/kuhyx/utils.git
synced 2026-11-14 20:11:00 +01:00
Grade crdt-sync and gatelock against 3.14 too, not just run on them
Some checks failed
crdt-sync pre-commit / pre-commit (push) Has been cancelled
crdt-sync tests / test (push) Has been cancelled
dependency freshness / dependencies on newest stable (push) Has been cancelled
file length / file-length (push) Has been cancelled
gatelock pre-commit / pre-commit (push) Has been cancelled
gatelock tests / test (push) Has been cancelled
md-naming / markdown naming convention (push) Has been cancelled
palette drift / palette (push) Has been cancelled
shared gate tests / gate unit tests (push) Has been cancelled
Some checks failed
crdt-sync pre-commit / pre-commit (push) Has been cancelled
crdt-sync tests / test (push) Has been cancelled
dependency freshness / dependencies on newest stable (push) Has been cancelled
file length / file-length (push) Has been cancelled
gatelock pre-commit / pre-commit (push) Has been cancelled
gatelock tests / test (push) Has been cancelled
md-naming / markdown naming convention (push) Has been cancelled
palette drift / palette (push) Has been cancelled
shared gate tests / gate unit tests (push) Has been cancelled
Both libraries had already moved `requires-python` to 3.14, but ruff, mypy and pylint were still grading against 3.10 -- three tools judging an interpreter nothing runs any more, and ruff withholding the pyupgrade fixes that only become safe at the newer target. `pin_ci_python.py` rewrites these three knobs. What the stale target was hiding: `datetime.timezone.utc` where `datetime.UTC` is now correct (UP017), a dead `timezone` import left behind by it, and ruff's stable formatter applying PEP 758 -- `except (A, B):` becomes `except A, B:`. That last one makes the source 3.14-only at the syntax level, which is what `requires-python = ">=3.14"` already promised; kuhy chose it deliberately over holding ruff a release back (2026-08-29). These two are libraries the apps install, so the floor matters more here than anywhere else in the fleet -- every consumer already pins >=3.14. Per project: ruff, ruff-format, mypy --strict and pylint clean, crdt-sync 432 tests and gatelock 389 tests, both at 100% line and branch coverage. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SfnJmxxsZ534AKk16rC2Gr
This commit is contained in:
parent
b914cc87fb
commit
305e59b3e8
@ -121,11 +121,11 @@ class FileCredentialStore:
|
||||
"""
|
||||
try:
|
||||
data = json.loads(self._path.read_text(encoding="utf-8"))
|
||||
except (OSError, ValueError):
|
||||
except OSError, ValueError:
|
||||
return None
|
||||
try:
|
||||
return FirebaseCredentials.from_json(data)
|
||||
except (KeyError, TypeError, ValueError):
|
||||
except KeyError, TypeError, ValueError:
|
||||
return None
|
||||
|
||||
def save(self, credentials: FirebaseCredentials) -> None:
|
||||
@ -144,4 +144,4 @@ class FileCredentialStore:
|
||||
|
||||
|
||||
def _utcnow() -> dt.datetime:
|
||||
return dt.datetime.now(dt.timezone.utc)
|
||||
return dt.datetime.now(dt.UTC)
|
||||
|
||||
@ -9,11 +9,11 @@ ties), without requiring synchronized clocks across devices.
|
||||
from __future__ import annotations
|
||||
|
||||
from dataclasses import dataclass
|
||||
from datetime import datetime, timezone
|
||||
from datetime import UTC, datetime
|
||||
import time
|
||||
|
||||
_ISO_PREFIX_LEN = 23 # len("YYYY-MM-DDTHH:MM:SS.mmm")
|
||||
_EPOCH = datetime(1970, 1, 1, tzinfo=timezone.utc)
|
||||
_EPOCH = datetime(1970, 1, 1, tzinfo=UTC)
|
||||
|
||||
|
||||
@dataclass(frozen=True, order=True)
|
||||
@ -66,7 +66,7 @@ class Hlc:
|
||||
comparison for the wall-clock component.
|
||||
"""
|
||||
seconds, millis = divmod(self.wall_time_ms, 1000)
|
||||
dt = datetime.fromtimestamp(seconds, tz=timezone.utc)
|
||||
dt = datetime.fromtimestamp(seconds, tz=UTC)
|
||||
iso = dt.strftime("%Y-%m-%dT%H:%M:%S")
|
||||
return f"{iso}.{millis:03d}Z-{self.counter:04x}-{self.node_id}"
|
||||
|
||||
@ -85,9 +85,7 @@ class Hlc:
|
||||
if not sep:
|
||||
msg = f"not a valid Hlc string: {text!r}"
|
||||
raise ValueError(msg)
|
||||
dt = datetime.strptime(iso_part, "%Y-%m-%dT%H:%M:%S.%f").replace(
|
||||
tzinfo=timezone.utc
|
||||
)
|
||||
dt = datetime.strptime(iso_part, "%Y-%m-%dT%H:%M:%S.%f").replace(tzinfo=UTC)
|
||||
delta = dt - _EPOCH
|
||||
wall_time_ms = (
|
||||
delta.days * 86_400_000 + delta.seconds * 1000 + delta.microseconds // 1000
|
||||
|
||||
@ -96,7 +96,7 @@ def _pull_remote_logs(
|
||||
continue
|
||||
try:
|
||||
remote_logs.append(ctx.decode(text))
|
||||
except (ValueError, KeyError, TypeError):
|
||||
except ValueError, KeyError, TypeError:
|
||||
_logger.warning(
|
||||
"Unparsable log pushed by device %r, skipping",
|
||||
other_device_id,
|
||||
|
||||
@ -53,7 +53,7 @@ def read_log(path: Path) -> Log:
|
||||
return {}
|
||||
try:
|
||||
return load_log(text)
|
||||
except (ValueError, KeyError, TypeError):
|
||||
except ValueError, KeyError, TypeError:
|
||||
return {}
|
||||
|
||||
|
||||
|
||||
@ -119,7 +119,7 @@ class FileSyncStateStore:
|
||||
"""Return the stored state, or a default one if unreadable."""
|
||||
try:
|
||||
data = json.loads(self._path.read_text(encoding="utf-8"))
|
||||
except (OSError, ValueError):
|
||||
except OSError, ValueError:
|
||||
return SyncState()
|
||||
if not isinstance(data, dict):
|
||||
return SyncState()
|
||||
|
||||
@ -53,7 +53,7 @@ def _auth(*, signed_in: bool = True) -> FirebaseTokenProvider:
|
||||
FirebaseCredentials(
|
||||
id_token=_FAKE_ID,
|
||||
refresh_token=_FAKE_REFRESH,
|
||||
expires_at=dt.datetime(2099, 1, 1, tzinfo=dt.timezone.utc),
|
||||
expires_at=dt.datetime(2099, 1, 1, tzinfo=dt.UTC),
|
||||
)
|
||||
if signed_in
|
||||
else None
|
||||
|
||||
@ -22,7 +22,7 @@ from crdt_sync import (
|
||||
)
|
||||
from crdt_sync import _firebase_auth as fa
|
||||
|
||||
_NOW = dt.datetime(2026, 8, 3, 12, tzinfo=dt.timezone.utc)
|
||||
_NOW = dt.datetime(2026, 8, 3, 12, tzinfo=dt.UTC)
|
||||
|
||||
# Fixture values referenced through names ruff's hardcoded-credential checks
|
||||
# (S105-S107) do not key off. Comparing an attribute called `id_token` to a
|
||||
|
||||
@ -20,7 +20,7 @@ from crdt_sync import (
|
||||
)
|
||||
from crdt_sync import _firebase_auth as fa
|
||||
|
||||
_NOW = dt.datetime(2026, 8, 3, 12, tzinfo=dt.timezone.utc)
|
||||
_NOW = dt.datetime(2026, 8, 3, 12, tzinfo=dt.UTC)
|
||||
|
||||
# Fixture values referenced through names ruff's hardcoded-credential checks
|
||||
# (S105-S107) do not key off. Comparing an attribute called `id_token` to a
|
||||
|
||||
@ -25,7 +25,7 @@ from crdt_sync import _firebase_auth as fa
|
||||
if TYPE_CHECKING:
|
||||
from pathlib import Path
|
||||
|
||||
_NOW = dt.datetime(2026, 8, 3, 12, tzinfo=dt.timezone.utc)
|
||||
_NOW = dt.datetime(2026, 8, 3, 12, tzinfo=dt.UTC)
|
||||
|
||||
# Fixture values referenced through names ruff's hardcoded-credential checks
|
||||
# (S105-S107) do not key off. Comparing an attribute called `id_token` to a
|
||||
|
||||
@ -21,7 +21,7 @@ from crdt_sync import (
|
||||
)
|
||||
from crdt_sync import _firebase_auth as fa
|
||||
|
||||
_NOW = dt.datetime(2026, 8, 3, 12, tzinfo=dt.timezone.utc)
|
||||
_NOW = dt.datetime(2026, 8, 3, 12, tzinfo=dt.UTC)
|
||||
|
||||
# Fixture values referenced through names ruff's hardcoded-credential checks
|
||||
# (S105-S107) do not key off. Comparing an attribute called `id_token` to a
|
||||
|
||||
@ -50,7 +50,7 @@ def _auth(*, signed_in: bool = True) -> FirebaseTokenProvider:
|
||||
FirebaseCredentials(
|
||||
id_token=_FAKE_ID,
|
||||
refresh_token=_FAKE_REFRESH,
|
||||
expires_at=dt.datetime(2099, 1, 1, tzinfo=dt.timezone.utc),
|
||||
expires_at=dt.datetime(2099, 1, 1, tzinfo=dt.UTC),
|
||||
)
|
||||
if signed_in
|
||||
else None
|
||||
|
||||
@ -14,7 +14,7 @@ dependencies = ["requests==2.34.2"]
|
||||
packages = ["crdt_sync", "crdt_sync.tests"]
|
||||
|
||||
[tool.ruff]
|
||||
target-version = "py310"
|
||||
target-version = "py314"
|
||||
include = ["*.py", "**/*.py"]
|
||||
exclude = [".git", ".venv", "__pycache__", "build", "dist", ".eggs"]
|
||||
|
||||
@ -58,7 +58,7 @@ line-ending = "auto"
|
||||
docstring-code-format = true
|
||||
|
||||
[tool.mypy]
|
||||
python_version = "3.10"
|
||||
python_version = "3.14"
|
||||
strict = true
|
||||
warn_return_any = true
|
||||
warn_unused_configs = true
|
||||
@ -86,7 +86,7 @@ exclude = [".venv/"]
|
||||
analyse-fallback-blocks = true
|
||||
persistent = true
|
||||
jobs = 0
|
||||
py-version = "3.10"
|
||||
py-version = "3.14"
|
||||
ignore = [".venv", "__pycache__"]
|
||||
ignore-patterns = [".*\\.pyi$"]
|
||||
|
||||
|
||||
@ -227,7 +227,7 @@ def main(argv: list[str] | None = None) -> int:
|
||||
config = FirebaseConfig.load()
|
||||
_logger.info(" .. linking onto %s (uid %s)", config.email, config.uid)
|
||||
linked_uid = link_google(config, token)
|
||||
except (LinkError, ConfigError, FirebaseAuthError):
|
||||
except LinkError, ConfigError, FirebaseAuthError:
|
||||
# logging.exception already renders the exception and its traceback.
|
||||
_logger.exception(" FAIL")
|
||||
return 1
|
||||
|
||||
@ -30,7 +30,7 @@ arms anyway. See :meth:`Arbiter.evaluate`.
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from datetime import datetime, timezone
|
||||
from datetime import UTC, datetime
|
||||
import logging
|
||||
import os
|
||||
from typing import IO, TYPE_CHECKING, Final
|
||||
@ -78,7 +78,7 @@ _HOLDER_FILENAME: Final = "holder.lock"
|
||||
|
||||
def _utc_now_iso() -> str:
|
||||
"""Return an ISO-8601 UTC timestamp, sortable as a plain string."""
|
||||
return datetime.now(tz=timezone.utc).isoformat()
|
||||
return datetime.now(tz=UTC).isoformat()
|
||||
|
||||
|
||||
class Arbiter:
|
||||
|
||||
@ -94,7 +94,7 @@ class Claim:
|
||||
disable_vt=bool(raw["disable_vt"]),
|
||||
instance_id=str(raw["instance_id"]),
|
||||
)
|
||||
except (KeyError, TypeError, ValueError):
|
||||
except KeyError, TypeError, ValueError:
|
||||
return None
|
||||
|
||||
def at_least_as_strong_as(self, other: Claim) -> bool:
|
||||
|
||||
@ -9,7 +9,7 @@ Re-exported from :mod:`gatelock._escape`, so existing imports keep working.
|
||||
from __future__ import annotations
|
||||
|
||||
from dataclasses import dataclass, field
|
||||
from datetime import datetime, timezone
|
||||
from datetime import UTC, datetime
|
||||
import logging
|
||||
from typing import Any
|
||||
|
||||
@ -67,7 +67,7 @@ class EscapeDraft:
|
||||
|
||||
def _today_iso() -> str:
|
||||
"""Return today's date as ``YYYY-MM-DD`` (UTC)."""
|
||||
return datetime.now(tz=timezone.utc).strftime(_DATE_FORMAT)
|
||||
return datetime.now(tz=UTC).strftime(_DATE_FORMAT)
|
||||
|
||||
|
||||
def _parse_iso(date_str: str) -> datetime | None:
|
||||
@ -77,7 +77,7 @@ def _parse_iso(date_str: str) -> datetime | None:
|
||||
silently counting it as zero would quietly widen the budget.
|
||||
"""
|
||||
try:
|
||||
return datetime.strptime(date_str, _DATE_FORMAT).replace(tzinfo=timezone.utc)
|
||||
return datetime.strptime(date_str, _DATE_FORMAT).replace(tzinfo=UTC)
|
||||
except ValueError as exc:
|
||||
_logger.warning(
|
||||
"escape history holds an unparsable date %r (%s) -- that entry is "
|
||||
|
||||
@ -140,7 +140,7 @@ class RandrBackend:
|
||||
"""Return the primary output's id, or None when RandR won't say."""
|
||||
try:
|
||||
return root.xrandr_get_output_primary().output
|
||||
except (OSError, ValueError, KeyError, AttributeError, TypeError):
|
||||
except OSError, ValueError, KeyError, AttributeError, TypeError:
|
||||
return None
|
||||
|
||||
def _crtc_rect(self, crtc: int, timestamp: int) -> OutputRect | None:
|
||||
|
||||
@ -100,7 +100,7 @@ def bind_scroll_keys(canvas: tk.Canvas, content: tk.Misc) -> None:
|
||||
target: tk.Misc = canvas
|
||||
try:
|
||||
target = canvas.winfo_toplevel()
|
||||
except (tk.TclError, KeyError, AttributeError):
|
||||
except tk.TclError, KeyError, AttributeError:
|
||||
# Reachable when the widget tree's root is not a real toplevel --
|
||||
# notably under tests that mock the Tk root. Degrade to binding on
|
||||
# the canvas rather than failing to build the viewport at all:
|
||||
|
||||
@ -97,7 +97,7 @@ def viewport_targets(canvas: tk.Misc, content: tk.Misc) -> list[tk.Misc]:
|
||||
targets: list[tk.Misc] = [canvas, content]
|
||||
try:
|
||||
targets.append(canvas.winfo_toplevel())
|
||||
except (tk.TclError, KeyError, AttributeError):
|
||||
except tk.TclError, KeyError, AttributeError:
|
||||
_logger.warning(
|
||||
"no toplevel for scroll viewport; user-input tracking is "
|
||||
"bound to the viewport only, so focus-following scrolling "
|
||||
|
||||
@ -37,7 +37,7 @@ from __future__ import annotations
|
||||
|
||||
import contextlib
|
||||
import tkinter as tk
|
||||
from typing import TYPE_CHECKING, Generic, TypeVar
|
||||
from typing import TYPE_CHECKING, TypeVar
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from collections.abc import Callable, Iterator
|
||||
@ -45,7 +45,7 @@ if TYPE_CHECKING:
|
||||
_W = TypeVar("_W", bound=tk.Misc)
|
||||
|
||||
|
||||
class WidgetGroup(Generic[_W]):
|
||||
class WidgetGroup[W: tk.Misc]:
|
||||
"""Every per-output copy of one logical widget.
|
||||
|
||||
Build one per logical widget, :meth:`add` a copy as each surface is
|
||||
|
||||
@ -21,7 +21,7 @@ randr = ["python-xlib==0.33"]
|
||||
include = ["gatelock*"]
|
||||
|
||||
[tool.ruff]
|
||||
target-version = "py310"
|
||||
target-version = "py314"
|
||||
include = ["*.py", "**/*.py"]
|
||||
exclude = [".git", ".venv", "__pycache__", "build", "dist", ".eggs"]
|
||||
|
||||
@ -70,7 +70,7 @@ line-ending = "auto"
|
||||
docstring-code-format = true
|
||||
|
||||
[tool.mypy]
|
||||
python_version = "3.10"
|
||||
python_version = "3.14"
|
||||
strict = true
|
||||
warn_return_any = true
|
||||
warn_unused_configs = true
|
||||
@ -98,7 +98,7 @@ exclude = [".venv/"]
|
||||
analyse-fallback-blocks = true
|
||||
persistent = true
|
||||
jobs = 0
|
||||
py-version = "3.10"
|
||||
py-version = "3.14"
|
||||
ignore = [".venv", "__pycache__"]
|
||||
ignore-patterns = [".*\\.pyi$"]
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user