mirror of
https://github.com/Alishahryar1/free-claude-code.git
synced 2026-07-10 00:14:16 +00:00
## Problem
Python 3.14 provides native lazy annotations, but the codebase still
relied on legacy future annotation imports. Those imports also made
type-only import cycles easier to hide instead of fixing ownership
boundaries.
## Changes
| Before | After |
| --- | --- |
| Python files used `from __future__ import annotations`. | Python files
rely on Python 3.14 native lazy annotations. |
| Some runtime modules used `TYPE_CHECKING` or local imports for
required dependencies. | Runtime modules use top-level owner-module
imports with explicit boundaries. |
| Local and GitHub guardrails only rejected type ignore suppressions. |
Local and GitHub guardrails reject type ignore suppressions and legacy
future annotation imports. |
| Agent docs only documented the no-type-ignore rule. | Agent docs
document the Python 3.14 annotation and import-boundary rules. |
<!-- greptile_comment -->
<details open><summary><h3>Greptile Summary</h3></summary>
This PR moves the codebase to Python 3.14 native lazy annotations. The
main changes are:
- Removed legacy `from __future__ import annotations` imports across
Python modules.
- Promoted selected runtime dependencies from `TYPE_CHECKING` or local
imports to explicit owner-module imports.
- Added local, GitHub, and contract-test guardrails to reject legacy
future annotation imports.
- Updated agent docs with the annotation and import-boundary rules.
- Bumped the package patch version for production-file changes.
</details>
<h3>Confidence Score: 5/5</h3>
Safe to merge with low risk.
The changes are mostly mechanical annotation cleanup with matching CI
and contract-test guardrails. Reviewed import-boundary updates did not
show a confirmed runtime cycle or dependency break.
No files require special attention.
<details><summary><h3><a href="https://www.greptile.com/trex"><img
alt="T-Rex"
src="https://greptile-static-assets.s3.amazonaws.com/trex/trex_green.svg"
height="20" align="absmiddle"></a> T-Rex Logs</h3></summary>
**What T-Rex did**
- Performed an end-to-end validation of the guardrail contract suite: an
environment check confirmed uv availability, a guardrail pytest run used
CPython 3.14.0 with 5 passing contract tests, 3 focused CI-script tests
passed, and the direct CI suppressions guardrail command (including the
legacy future-annotations grep) also passed.
<a
href="https://app.greptile.com/trex/runs/13303335/artifacts"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://greptile-static-assets.s3.amazonaws.com/badges/ViewAllArtifactsDark.svg?v=4"><source
media="(prefers-color-scheme: light)"
srcset="https://greptile-static-assets.s3.amazonaws.com/badges/ViewAllArtifacts.svg?v=4"><img
alt="View all artifacts"
src="https://greptile-static-assets.s3.amazonaws.com/badges/ViewAllArtifacts.svg?v=4"></picture></a>
<sub><a href="https://www.greptile.com/trex"><img alt="T-Rex"
src="https://greptile-static-assets.s3.amazonaws.com/trex/trex_green.svg"
height="14" align="absmiddle"></a> Ran code and verified through
T-Rex</sub>
</details>
<details open><summary><h3>Important Files Changed</h3></summary>
| Filename | Overview |
|----------|----------|
| api/runtime.py | Moves messaging, CLI manager, session, limiter, and
tree dependencies from local/type-checking imports to explicit top-level
owner-module imports. |
| messaging/platforms/telegram.py | Removes future annotations and
promotes Telegram SDK type imports into the existing availability guard.
|
| messaging/platforms/telegram_inbound.py | Removes future annotations
and imports Telegram SDK types at module scope for inbound
normalization. |
| tests/contracts/test_import_boundaries.py | Adds an AST contract that
rejects legacy future annotation imports across Python files. |
| scripts/ci.sh | Extends the local suppression check to reject legacy
future annotation imports alongside type-ignore suppressions. |
| scripts/ci.ps1 | Mirrors the local PowerShell CI suppression check for
legacy future annotations. |
| .github/workflows/tests.yml | Renames and broadens the GitHub
guardrail job to reject both type suppressions and legacy future
annotations. |
| pyproject.toml | Bumps the patch version for production-file changes.
|
</details>
<details open><summary><h3>Sequence Diagram</h3></summary>
<a href="#gh-light-mode-only">
```mermaid
%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
participant Dev as Developer/CI
participant Guard as Suppression guard
participant AST as Import-boundary contract test
participant Py as Python modules
Dev->>Guard: Run local/GitHub suppression check
Guard->>Py: "Scan *.py for type ignores and future annotations"
Guard-->>Dev: Fail if legacy annotation import remains
Dev->>AST: Run pytest contract tests
AST->>Py: Parse imports with ast
AST-->>Dev: Assert no future annotations/import-boundary violations
Py-->>Dev: Use Python 3.14 native lazy annotations
```
</a>
<a href="#gh-dark-mode-only">
```mermaid
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
participant Dev as Developer/CI
participant Guard as Suppression guard
participant AST as Import-boundary contract test
participant Py as Python modules
Dev->>Guard: Run local/GitHub suppression check
Guard->>Py: "Scan *.py for type ignores and future annotations"
Guard-->>Dev: Fail if legacy annotation import remains
Dev->>AST: Run pytest contract tests
AST->>Py: Parse imports with ast
AST-->>Dev: Assert no future annotations/import-boundary violations
Py-->>Dev: Use Python 3.14 native lazy annotations
```
</a>
</details>
<sub>Reviews (2): Last reviewed commit: ["Remove legacy future
annotations
import"](6e6cda69da)
| [Re-trigger
Greptile](https://app.greptile.com/api/retrigger?id=41875785)</sub>
<!-- /greptile_comment -->
210 lines
5.1 KiB
PowerShell
210 lines
5.1 KiB
PowerShell
param(
|
|
[string[]] $Only = @(),
|
|
[string[]] $Skip = @(),
|
|
[switch] $DryRun,
|
|
[switch] $Help,
|
|
[Parameter(ValueFromRemainingArguments = $true)]
|
|
[object[]] $RemainingArgs = @()
|
|
)
|
|
|
|
Set-StrictMode -Version Latest
|
|
$ErrorActionPreference = "Stop"
|
|
|
|
$CheckOrder = @(
|
|
"suppressions",
|
|
"ruff-format",
|
|
"ruff-check",
|
|
"ty",
|
|
"pytest"
|
|
)
|
|
|
|
function Show-Usage {
|
|
@"
|
|
Usage: ci.ps1 [options]
|
|
|
|
Runs the local sequence for the same check IDs enforced by GitHub CI.
|
|
Requires uv on PATH when running ruff, ty, or pytest checks.
|
|
Local ruff checks repair formatting and autofixable lint before later checks.
|
|
|
|
Checks (in order):
|
|
suppressions Ban type ignores and legacy future annotations
|
|
ruff-format uv run ruff format
|
|
ruff-check uv run ruff check --fix
|
|
ty uv run ty check
|
|
pytest uv run pytest -v --tb=short
|
|
|
|
Options:
|
|
-Only ID Run only the given check (repeatable)
|
|
-Skip ID Skip the given check (repeatable)
|
|
-DryRun Print commands without running them.
|
|
-Help Show this help text.
|
|
"@
|
|
}
|
|
|
|
function Write-Step {
|
|
param([string] $Message)
|
|
|
|
Write-Host ""
|
|
Write-Host "==> $Message"
|
|
}
|
|
|
|
function Format-Argument {
|
|
param([string] $Value)
|
|
|
|
if ($Value -match '^[A-Za-z0-9_./:@%+=,\[\]-]+$') {
|
|
return $Value
|
|
}
|
|
|
|
return "'" + ($Value -replace "'", "''") + "'"
|
|
}
|
|
|
|
function Invoke-CiCommand {
|
|
param(
|
|
[string] $FilePath,
|
|
[string[]] $Arguments = @()
|
|
)
|
|
|
|
$parts = @($FilePath) + $Arguments
|
|
$commandText = ($parts | ForEach-Object { Format-Argument ([string] $_) }) -join " "
|
|
Write-Host "+ $commandText"
|
|
|
|
if (-not $DryRun) {
|
|
& $FilePath @Arguments
|
|
if ($LASTEXITCODE -ne 0) {
|
|
throw "Command failed with exit code ${LASTEXITCODE}: $commandText"
|
|
}
|
|
}
|
|
}
|
|
|
|
function Test-ValidCheckId {
|
|
param([string] $CheckId)
|
|
|
|
return $CheckOrder -contains $CheckId
|
|
}
|
|
|
|
function Assert-ValidCheckId {
|
|
param([string] $CheckId)
|
|
|
|
if (-not (Test-ValidCheckId $CheckId)) {
|
|
throw "unknown check id: $CheckId (expected one of: $($CheckOrder -join ', '))"
|
|
}
|
|
}
|
|
|
|
function Test-ShouldRunCheck {
|
|
param([string] $CheckId)
|
|
|
|
if ($Only.Count -gt 0 -and ($Only -notcontains $CheckId)) {
|
|
return $false
|
|
}
|
|
|
|
if ($Skip -contains $CheckId) {
|
|
return $false
|
|
}
|
|
|
|
return $true
|
|
}
|
|
|
|
function Assert-UvAvailable {
|
|
if (-not (Get-Command uv -ErrorAction SilentlyContinue)) {
|
|
throw "uv is required but was not found on PATH. Install uv first (see README or scripts/install.ps1)."
|
|
}
|
|
}
|
|
|
|
function Test-SelectedChecksNeedUv {
|
|
if ($DryRun) {
|
|
return $false
|
|
}
|
|
|
|
foreach ($checkId in $CheckOrder) {
|
|
if ((Test-ShouldRunCheck $checkId) -and $checkId -ne "suppressions") {
|
|
return $true
|
|
}
|
|
}
|
|
|
|
return $false
|
|
}
|
|
|
|
function Invoke-SuppressionsCheck {
|
|
Write-Step "Ban suppressions and legacy annotations"
|
|
$pattern = '# type: ignore|# ty: ignore|from __future__ import annotations'
|
|
Write-Host "+ Get-ChildItem -Recurse -Filter *.py (excluding .venv, .git) | Select-String '$pattern'"
|
|
|
|
if (-not $DryRun) {
|
|
$matches = Get-ChildItem -Path . -Recurse -Filter *.py -File |
|
|
Where-Object {
|
|
$full = $_.FullName
|
|
$full -notmatch '[\\/]\.venv[\\/]' -and
|
|
$full -notmatch '[\\/]\.git[\\/]'
|
|
} |
|
|
Select-String -Pattern $pattern
|
|
|
|
if ($matches) {
|
|
$matches | ForEach-Object { Write-Host $_.Line }
|
|
throw "type: ignore / ty: ignore comments and legacy future annotations are not allowed. Fix the underlying type/import issue instead."
|
|
}
|
|
}
|
|
}
|
|
|
|
function Invoke-RuffFormatCheck {
|
|
Write-Step "ruff format"
|
|
Invoke-CiCommand -FilePath "uv" -Arguments @("run", "ruff", "format")
|
|
}
|
|
|
|
function Invoke-RuffLintCheck {
|
|
Write-Step "ruff check --fix"
|
|
Invoke-CiCommand -FilePath "uv" -Arguments @("run", "ruff", "check", "--fix")
|
|
}
|
|
|
|
function Invoke-TyCheck {
|
|
Write-Step "ty check"
|
|
Invoke-CiCommand -FilePath "uv" -Arguments @("run", "ty", "check")
|
|
}
|
|
|
|
function Invoke-PytestCheck {
|
|
Write-Step "pytest"
|
|
Invoke-CiCommand -FilePath "uv" -Arguments @("run", "pytest", "-v", "--tb=short")
|
|
}
|
|
|
|
function Invoke-Check {
|
|
param([string] $CheckId)
|
|
|
|
switch ($CheckId) {
|
|
"suppressions" { Invoke-SuppressionsCheck }
|
|
"ruff-format" { Invoke-RuffFormatCheck }
|
|
"ruff-check" { Invoke-RuffLintCheck }
|
|
"ty" { Invoke-TyCheck }
|
|
"pytest" { Invoke-PytestCheck }
|
|
default { throw "unknown check id: $CheckId" }
|
|
}
|
|
}
|
|
|
|
if ($Help) {
|
|
Show-Usage
|
|
return
|
|
}
|
|
|
|
if ($RemainingArgs.Count -gt 0) {
|
|
Show-Usage
|
|
throw "Unknown option: $($RemainingArgs -join ' ')"
|
|
}
|
|
|
|
foreach ($checkId in $Only) {
|
|
Assert-ValidCheckId $checkId
|
|
}
|
|
|
|
foreach ($checkId in $Skip) {
|
|
Assert-ValidCheckId $checkId
|
|
}
|
|
|
|
if (Test-SelectedChecksNeedUv) {
|
|
Assert-UvAvailable
|
|
}
|
|
|
|
foreach ($checkId in $CheckOrder) {
|
|
if (Test-ShouldRunCheck $checkId) {
|
|
Invoke-Check $checkId
|
|
}
|
|
}
|
|
|
|
Write-Host ""
|
|
Write-Host "All selected CI checks passed."
|