Skip to content

feat(python): upgrade to Python 3.14#223

Open
saidsef wants to merge 1 commit intomainfrom
python-3.14-upgrade
Open

feat(python): upgrade to Python 3.14#223
saidsef wants to merge 1 commit intomainfrom
python-3.14-upgrade

Conversation

@saidsef
Copy link
Copy Markdown
Owner

@saidsef saidsef commented Apr 26, 2026

What this does

Upgrades the project to Python 3.14. The .python-version and Dockerfile already targeted 3.14 — this brings the rest of the project in sync and cleans up patterns that accumulated as the project grew from 3.9 → 3.12 → 3.14.

Dependency changes

  • Dropped requests in favour of httpx (which was already the only HTTP client used by fastmcp)
  • Replaced mypy with pyrightfastmcp itself ships pyright-compatible stubs, and pyright handles PEP 695 syntax better
  • Relaxed exact pins on fastmcp[apps] and uv

Typing

  • Optional[X]X | None, Dict[K, V]dict[K, V] throughout
  • TypedDicts rewritten as PEP 695 functional type aliases (type X = TypedDict(...))

Code cleanup

  • IPIntegration.__init__ simplified: 12 lines → 2 using or fallbacks
  • IPIntegration.get_ipv6_info now uses a context manager for the httpx client and drops the urllib3 monkey-patch
  • _PermissiveGitHubProvider moved to module level (was defined inside get_oauth_verifier())
  • Fixed a bug where add_pr_comments called httpx.get with a json= kwarg (should be httpx.post)

What might break

  • Projects depending on Python < 3.14 can no longer run this
  • Any downstream code that imported from requests directly via this package will break (none in-tree)

Bugs fixed during review

Tool registration broken in Python 3.14

The register_tools() method used inspect.ismethod() to detect bound methods, but Python 3.14 changed the behavior — bound methods now return False. This caused all 20 MCP tools to be silently skipped during registration.

Fix: Changed inspect.isfunction(method) or inspect.ismethod(method)inspect.isroutine(method) which works for both.

ResponseCachingMiddleware causing tools/list to fail

The ResponseCachingMiddleware was added with ttl=0 to disable caching, but FastMCP 3.2.4 rejects ttl=0 as invalid, causing every tools/list request to fail with "TTL is invalid" error.

Fix: Removed the middleware entirely since tool list changes are detectable via the listChanged capability.

@saidsef saidsef self-assigned this Apr 26, 2026
@saidsef saidsef added python Pull requests that update python code feat type-safety maintenance refactoring labels Apr 26, 2026
@codacy-production
Copy link
Copy Markdown

codacy-production Bot commented Apr 26, 2026

Up to standards ✅

🟢 Issues 0 issues

Results:
0 new issues

View in Codacy

🟢 Metrics -5 complexity

Metric Results
Complexity -5

View in Codacy

NEW Get contextual insights on your PRs based on Codacy's metrics, along with PR and Jira context, without leaving GitHub. Enable AI reviewer
TIP This summary will be updated as you push new changes.

@saidsef saidsef changed the title feat!: upgrade to Python 3.14 feat(httpx): upgrade to Python 3.14 Apr 26, 2026
@saidsef saidsef changed the title feat(httpx): upgrade to Python 3.14 feat(py): upgrade to Python 3.14 Apr 26, 2026
@github-actions
Copy link
Copy Markdown

github-actions Bot commented Apr 26, 2026

Dependency Review

The following issues were found:
  • ✅ 0 vulnerable package(s)
  • ✅ 0 package(s) with incompatible licenses
  • ✅ 0 package(s) with invalid SPDX license definitions
  • ⚠️ 43 package(s) with unknown licenses.
  • ⚠️ 2 packages with OpenSSF Scorecard issues.
See the Details below.

License Issues

pyproject.toml

PackageVersionLicenseIssue Type
httpx>= 0.28.1NullUnknown License

requirements.txt

PackageVersionLicenseIssue Type
authlib1.7.0NullUnknown License
cachetools7.0.6NullUnknown License
click8.3.3NullUnknown License
cryptography47.0.0NullUnknown License
cyclopts4.11.0NullUnknown License
fastmcp3.2.4NullUnknown License
griffelib2.0.2NullUnknown License
idna3.13NullUnknown License
joserfc1.6.4NullUnknown License
opentelemetry-api1.41.1NullUnknown License
packaging26.2NullUnknown License
prefab-ui0.19.1NullUnknown License
pydantic2.13.3NullUnknown License
pytest9.0.3NullUnknown License
ruff0.15.12NullUnknown License
sse-starlette3.4.1NullUnknown License
uv0.11.7NullUnknown License
uvicorn0.46.0NullUnknown License
zipp3.23.1NullUnknown License
certifi2026.4.22NullUnknown License

uv.lock

PackageVersionLicenseIssue Type
authlib1.7.0NullUnknown License
cachetools7.0.6NullUnknown License
click8.3.3NullUnknown License
cryptography47.0.0NullUnknown License
cyclopts4.11.0NullUnknown License
docstring-parser0.18.0NullUnknown License
fastmcp3.2.4NullUnknown License
griffelib2.0.2NullUnknown License
idna3.13NullUnknown License
joserfc1.6.4NullUnknown License
opentelemetry-api1.41.1NullUnknown License
packaging26.2NullUnknown License
prefab-ui0.19.1NullUnknown License
pydantic2.13.3NullUnknown License
pydantic-settings2.14.0NullUnknown License
pytest9.0.3NullUnknown License
ruff0.15.12NullUnknown License
sse-starlette3.4.1NullUnknown License
uv0.11.7NullUnknown License
uvicorn0.46.0NullUnknown License
zipp3.23.1NullUnknown License
certifi2026.4.22NullUnknown License

OpenSSF Scorecard

Scorecard details
PackageVersionScoreDetails
pip/httpx >= 0.28.1 UnknownUnknown
pip/authlib 1.7.0 UnknownUnknown
pip/cachetools 7.0.6 UnknownUnknown
pip/certifi 2026.4.22 🟢 6.6
Details
CheckScoreReason
Maintained🟢 1010 commit(s) and 2 issue activity found in the last 90 days -- score normalized to 10
Security-Policy🟢 10security policy file detected
Binary-Artifacts🟢 10no binaries found in the repo
Code-Review🟢 5Found 1/2 approved changesets -- score normalized to 5
Dangerous-Workflow🟢 10no dangerous workflow patterns detected
Pinned-Dependencies🟢 5dependency not pinned by hash detected -- score normalized to 5
Token-Permissions🟢 10GitHub workflow tokens follow principle of least privilege
CII-Best-Practices⚠️ 0no effort to earn an OpenSSF best practices badge detected
Fuzzing⚠️ 0project is not fuzzed
License🟢 9license file detected
Signed-Releases⚠️ -1no releases found
Branch-Protection⚠️ 0branch protection not enabled on development/release branches
Packaging🟢 10packaging workflow detected
SAST⚠️ 0SAST tool is not run on all commits -- score normalized to 0
pip/click 8.3.3 UnknownUnknown
pip/cryptography 47.0.0 UnknownUnknown
pip/cyclopts 4.11.0 UnknownUnknown
pip/fastmcp 3.2.4 UnknownUnknown
pip/griffelib 2.0.2 UnknownUnknown
pip/idna 3.13 UnknownUnknown
pip/iniconfig 2.3.0 UnknownUnknown
pip/joserfc 1.6.4 UnknownUnknown
pip/nodeenv 1.10.0 ⚠️ 2.8
Details
CheckScoreReason
Maintained⚠️ 00 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0
Code-Review⚠️ 1Found 5/30 approved changesets -- score normalized to 1
Dangerous-Workflow🟢 10no dangerous workflow patterns detected
Binary-Artifacts🟢 10no binaries found in the repo
Packaging⚠️ -1packaging workflow not detected
Pinned-Dependencies⚠️ 0dependency not pinned by hash detected -- score normalized to 0
Token-Permissions⚠️ 0detected GitHub workflow tokens with excessive permissions
CII-Best-Practices⚠️ 0no effort to earn an OpenSSF best practices badge detected
Security-Policy⚠️ 0security policy file not detected
Fuzzing⚠️ 0project is not fuzzed
License🟢 9license file detected
Signed-Releases⚠️ -1no releases found
Branch-Protection⚠️ 0branch protection not enabled on development/release branches
SAST⚠️ 0SAST tool is not run on all commits -- score normalized to 0
pip/opentelemetry-api 1.41.1 UnknownUnknown
pip/packaging 26.2 UnknownUnknown
pip/pluggy 1.6.0 UnknownUnknown
pip/prefab-ui 0.19.1 UnknownUnknown
pip/pydantic 2.13.3 UnknownUnknown
pip/pydantic-core 2.46.3 🟢 6.7
Details
CheckScoreReason
Maintained🟢 1030 commit(s) and 16 issue activity found in the last 90 days -- score normalized to 10
Code-Review🟢 10all changesets reviewed
Dangerous-Workflow🟢 10no dangerous workflow patterns detected
CII-Best-Practices⚠️ 0no effort to earn an OpenSSF best practices badge detected
Binary-Artifacts🟢 10no binaries found in the repo
Token-Permissions⚠️ 0detected GitHub workflow tokens with excessive permissions
Pinned-Dependencies🟢 8dependency not pinned by hash detected -- score normalized to 8
License🟢 10license file detected
Fuzzing🟢 10project is fuzzed
Signed-Releases⚠️ 0Project has not signed or included provenance with any releases.
Security-Policy🟢 10security policy file detected
Branch-Protection🟢 4branch protection is not maximal on development and all release branches
Packaging🟢 10packaging workflow detected
SAST⚠️ 0SAST tool is not run on all commits -- score normalized to 0
pip/pyright 1.1.409 🟢 3.5
Details
CheckScoreReason
Maintained⚠️ 00 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0
Dangerous-Workflow🟢 10no dangerous workflow patterns detected
Code-Review⚠️ 0Found 1/30 approved changesets -- score normalized to 0
Binary-Artifacts🟢 10no binaries found in the repo
Token-Permissions⚠️ 0detected GitHub workflow tokens with excessive permissions
CII-Best-Practices⚠️ 0no effort to earn an OpenSSF best practices badge detected
Security-Policy⚠️ 0security policy file not detected
Fuzzing⚠️ 0project is not fuzzed
License🟢 10license file detected
Signed-Releases⚠️ -1no releases found
Branch-Protection🟢 3branch protection is not maximal on development and all release branches
Pinned-Dependencies⚠️ 0dependency not pinned by hash detected -- score normalized to 0
Packaging🟢 10packaging workflow detected
SAST⚠️ 0SAST tool is not run on all commits -- score normalized to 0
pip/pytest 9.0.3 UnknownUnknown
pip/ruff 0.15.12 UnknownUnknown
pip/sse-starlette 3.4.1 UnknownUnknown
pip/uv 0.11.7 UnknownUnknown
pip/uvicorn 0.46.0 UnknownUnknown
pip/zipp 3.23.1 UnknownUnknown
pip/authlib 1.7.0 UnknownUnknown
pip/cachetools 7.0.6 UnknownUnknown
pip/certifi 2026.4.22 🟢 6.6
Details
CheckScoreReason
Maintained🟢 1010 commit(s) and 2 issue activity found in the last 90 days -- score normalized to 10
Security-Policy🟢 10security policy file detected
Binary-Artifacts🟢 10no binaries found in the repo
Code-Review🟢 5Found 1/2 approved changesets -- score normalized to 5
Dangerous-Workflow🟢 10no dangerous workflow patterns detected
Pinned-Dependencies🟢 5dependency not pinned by hash detected -- score normalized to 5
Token-Permissions🟢 10GitHub workflow tokens follow principle of least privilege
CII-Best-Practices⚠️ 0no effort to earn an OpenSSF best practices badge detected
Fuzzing⚠️ 0project is not fuzzed
License🟢 9license file detected
Signed-Releases⚠️ -1no releases found
Branch-Protection⚠️ 0branch protection not enabled on development/release branches
Packaging🟢 10packaging workflow detected
SAST⚠️ 0SAST tool is not run on all commits -- score normalized to 0
pip/click 8.3.3 UnknownUnknown
pip/cryptography 47.0.0 UnknownUnknown
pip/cyclopts 4.11.0 UnknownUnknown
pip/docstring-parser 0.18.0 UnknownUnknown
pip/fastmcp 3.2.4 UnknownUnknown
pip/griffelib 2.0.2 UnknownUnknown
pip/idna 3.13 UnknownUnknown
pip/iniconfig 2.3.0 UnknownUnknown
pip/joserfc 1.6.4 UnknownUnknown
pip/nodeenv 1.10.0 ⚠️ 2.8
Details
CheckScoreReason
Maintained⚠️ 00 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0
Code-Review⚠️ 1Found 5/30 approved changesets -- score normalized to 1
Dangerous-Workflow🟢 10no dangerous workflow patterns detected
Binary-Artifacts🟢 10no binaries found in the repo
Packaging⚠️ -1packaging workflow not detected
Pinned-Dependencies⚠️ 0dependency not pinned by hash detected -- score normalized to 0
Token-Permissions⚠️ 0detected GitHub workflow tokens with excessive permissions
CII-Best-Practices⚠️ 0no effort to earn an OpenSSF best practices badge detected
Security-Policy⚠️ 0security policy file not detected
Fuzzing⚠️ 0project is not fuzzed
License🟢 9license file detected
Signed-Releases⚠️ -1no releases found
Branch-Protection⚠️ 0branch protection not enabled on development/release branches
SAST⚠️ 0SAST tool is not run on all commits -- score normalized to 0
pip/opentelemetry-api 1.41.1 UnknownUnknown
pip/packaging 26.2 UnknownUnknown
pip/pluggy 1.6.0 UnknownUnknown
pip/prefab-ui 0.19.1 UnknownUnknown
pip/pydantic 2.13.3 UnknownUnknown
pip/pydantic-core 2.46.3 🟢 6.7
Details
CheckScoreReason
Maintained🟢 1030 commit(s) and 16 issue activity found in the last 90 days -- score normalized to 10
Code-Review🟢 10all changesets reviewed
Dangerous-Workflow🟢 10no dangerous workflow patterns detected
CII-Best-Practices⚠️ 0no effort to earn an OpenSSF best practices badge detected
Binary-Artifacts🟢 10no binaries found in the repo
Token-Permissions⚠️ 0detected GitHub workflow tokens with excessive permissions
Pinned-Dependencies🟢 8dependency not pinned by hash detected -- score normalized to 8
License🟢 10license file detected
Fuzzing🟢 10project is fuzzed
Signed-Releases⚠️ 0Project has not signed or included provenance with any releases.
Security-Policy🟢 10security policy file detected
Branch-Protection🟢 4branch protection is not maximal on development and all release branches
Packaging🟢 10packaging workflow detected
SAST⚠️ 0SAST tool is not run on all commits -- score normalized to 0
pip/pydantic-settings 2.14.0 UnknownUnknown
pip/pyright 1.1.409 🟢 3.5
Details
CheckScoreReason
Maintained⚠️ 00 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0
Dangerous-Workflow🟢 10no dangerous workflow patterns detected
Code-Review⚠️ 0Found 1/30 approved changesets -- score normalized to 0
Binary-Artifacts🟢 10no binaries found in the repo
Token-Permissions⚠️ 0detected GitHub workflow tokens with excessive permissions
CII-Best-Practices⚠️ 0no effort to earn an OpenSSF best practices badge detected
Security-Policy⚠️ 0security policy file not detected
Fuzzing⚠️ 0project is not fuzzed
License🟢 10license file detected
Signed-Releases⚠️ -1no releases found
Branch-Protection🟢 3branch protection is not maximal on development and all release branches
Pinned-Dependencies⚠️ 0dependency not pinned by hash detected -- score normalized to 0
Packaging🟢 10packaging workflow detected
SAST⚠️ 0SAST tool is not run on all commits -- score normalized to 0
pip/pytest 9.0.3 UnknownUnknown
pip/ruff 0.15.12 UnknownUnknown
pip/sse-starlette 3.4.1 UnknownUnknown
pip/uv 0.11.7 UnknownUnknown
pip/uvicorn 0.46.0 UnknownUnknown
pip/zipp 3.23.1 UnknownUnknown

Scanned Files

  • pyproject.toml
  • requirements.txt
  • uv.lock

@saidsef saidsef changed the title feat(py): upgrade to Python 3.14 feat!: upgrade to Python 3.14 Apr 26, 2026
github-actions[bot]
github-actions Bot previously approved these changes Apr 26, 2026
github-actions[bot]
github-actions Bot previously approved these changes Apr 26, 2026
github-actions[bot]
github-actions Bot previously approved these changes Apr 26, 2026
github-actions[bot]
github-actions Bot previously approved these changes Apr 26, 2026
github-actions[bot]
github-actions Bot previously approved these changes Apr 26, 2026
github-actions[bot]
github-actions Bot previously approved these changes Apr 26, 2026
@saidsef saidsef dismissed github-actions[bot]’s stale review April 26, 2026 22:38

The merge-base changed after approval.

@saidsef saidsef force-pushed the python-3.14-upgrade branch from 08271e7 to cd12d13 Compare April 26, 2026 22:38
@saidsef saidsef changed the title feat!: upgrade to Python 3.14 feat(python): upgrade to Python 3.14 Apr 26, 2026
github-actions[bot]
github-actions Bot previously approved these changes Apr 26, 2026
github-actions[bot]
github-actions Bot previously approved these changes Apr 26, 2026
…ve requests dependency

Upgrades the project to Python 3.14.

- Dropped `requests` in favour of `httpx`
- Replaced `mypy` with `pyright`
- Updated authlib to 1.7.0 (fixes GHSA-jj8c-mmj3-mmgv)
- TypedDicts rewritten as PEP 695 functional type aliases
- `inspect.isroutine()` instead of `ismethod()`/`isfunction()` for Python 3.14 compatibility
- Removed `ResponseCachingMiddleware` which caused `tools/list` failure in FastMCP 3.2.4
@saidsef saidsef force-pushed the python-3.14-upgrade branch from 04b4e99 to 79791ce Compare April 26, 2026 22:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant