safeuploads 1.1.2__tar.gz → 1.1.3__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (96) hide show
  1. {safeuploads-1.1.2 → safeuploads-1.1.3}/.github/workflows/lint-and-test.yml +28 -0
  2. {safeuploads-1.1.2 → safeuploads-1.1.3}/CHANGELOG.md +9 -0
  3. {safeuploads-1.1.2 → safeuploads-1.1.3}/PKG-INFO +1 -1
  4. {safeuploads-1.1.2 → safeuploads-1.1.3}/pyproject.toml +10 -1
  5. {safeuploads-1.1.2 → safeuploads-1.1.3}/safeuploads/protocols.py +6 -5
  6. {safeuploads-1.1.2 → safeuploads-1.1.3}/uv.lock +28 -1
  7. {safeuploads-1.1.2 → safeuploads-1.1.3}/.github/CODEOWNERS +0 -0
  8. {safeuploads-1.1.2 → safeuploads-1.1.3}/.github/FUNDING.yml +0 -0
  9. {safeuploads-1.1.2 → safeuploads-1.1.3}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
  10. {safeuploads-1.1.2 → safeuploads-1.1.3}/.github/ISSUE_TEMPLATE/config.yml +0 -0
  11. {safeuploads-1.1.2 → safeuploads-1.1.3}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
  12. {safeuploads-1.1.2 → safeuploads-1.1.3}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
  13. {safeuploads-1.1.2 → safeuploads-1.1.3}/.github/agents/se-gitops-ci-specialist.agent.md +0 -0
  14. {safeuploads-1.1.2 → safeuploads-1.1.3}/.github/agents/se-security-reviewer.agent.md +0 -0
  15. {safeuploads-1.1.2 → safeuploads-1.1.3}/.github/agents/test-implementor.agent.md +0 -0
  16. {safeuploads-1.1.2 → safeuploads-1.1.3}/.github/agents/test-reviewer.agent.md +0 -0
  17. {safeuploads-1.1.2 → safeuploads-1.1.3}/.github/copilot-instructions.md +0 -0
  18. {safeuploads-1.1.2 → safeuploads-1.1.3}/.github/dependabot.yml +0 -0
  19. {safeuploads-1.1.2 → safeuploads-1.1.3}/.github/instructions/agents.instructions.md +0 -0
  20. {safeuploads-1.1.2 → safeuploads-1.1.3}/.github/instructions/github-actions-ci-cd-best-practices.instructions.md +0 -0
  21. {safeuploads-1.1.2 → safeuploads-1.1.3}/.github/instructions/instructions.instructions.md +0 -0
  22. {safeuploads-1.1.2 → safeuploads-1.1.3}/.github/instructions/prompt.instructions.md +0 -0
  23. {safeuploads-1.1.2 → safeuploads-1.1.3}/.github/instructions/python.instructions.md +0 -0
  24. {safeuploads-1.1.2 → safeuploads-1.1.3}/.github/instructions/security-and-owasp.instructions.md +0 -0
  25. {safeuploads-1.1.2 → safeuploads-1.1.3}/.github/scripts/check_conventional_commits.py +0 -0
  26. {safeuploads-1.1.2 → safeuploads-1.1.3}/.github/scripts/smoke_import.py +0 -0
  27. {safeuploads-1.1.2 → safeuploads-1.1.3}/.github/workflows/audit-safeuploads.yml +0 -0
  28. {safeuploads-1.1.2 → safeuploads-1.1.3}/.github/workflows/conventional-commits.yml +0 -0
  29. {safeuploads-1.1.2 → safeuploads-1.1.3}/.github/workflows/docs.yml +0 -0
  30. {safeuploads-1.1.2 → safeuploads-1.1.3}/.github/workflows/fuzz.yml +0 -0
  31. {safeuploads-1.1.2 → safeuploads-1.1.3}/.github/workflows/mirror.yml +0 -0
  32. {safeuploads-1.1.2 → safeuploads-1.1.3}/.github/workflows/publish-safeuploads.yml +0 -0
  33. {safeuploads-1.1.2 → safeuploads-1.1.3}/.github/workflows/test-matrix-safeuploads.yml +0 -0
  34. {safeuploads-1.1.2 → safeuploads-1.1.3}/.gitignore +0 -0
  35. {safeuploads-1.1.2 → safeuploads-1.1.3}/CODE_OF_CONDUCT.md +0 -0
  36. {safeuploads-1.1.2 → safeuploads-1.1.3}/CONTRIBUTING.md +0 -0
  37. {safeuploads-1.1.2 → safeuploads-1.1.3}/LICENSE.md +0 -0
  38. {safeuploads-1.1.2 → safeuploads-1.1.3}/README.md +0 -0
  39. {safeuploads-1.1.2 → safeuploads-1.1.3}/SECURITY.md +0 -0
  40. {safeuploads-1.1.2 → safeuploads-1.1.3}/docs/api.md +0 -0
  41. {safeuploads-1.1.2 → safeuploads-1.1.3}/docs/index.md +0 -0
  42. {safeuploads-1.1.2 → safeuploads-1.1.3}/docs/rate-limiting.md +0 -0
  43. {safeuploads-1.1.2 → safeuploads-1.1.3}/docs/security/architecture.md +0 -0
  44. {safeuploads-1.1.2 → safeuploads-1.1.3}/docs/security/integration-checklist.md +0 -0
  45. {safeuploads-1.1.2 → safeuploads-1.1.3}/docs/security/threat-model.md +0 -0
  46. {safeuploads-1.1.2 → safeuploads-1.1.3}/examples/README.md +0 -0
  47. {safeuploads-1.1.2 → safeuploads-1.1.3}/examples/fastapi_example.py +0 -0
  48. {safeuploads-1.1.2 → safeuploads-1.1.3}/mkdocs.yml +0 -0
  49. {safeuploads-1.1.2 → safeuploads-1.1.3}/safeuploads/__init__.py +0 -0
  50. {safeuploads-1.1.2 → safeuploads-1.1.3}/safeuploads/audit.py +0 -0
  51. {safeuploads-1.1.2 → safeuploads-1.1.3}/safeuploads/config.py +0 -0
  52. {safeuploads-1.1.2 → safeuploads-1.1.3}/safeuploads/enums.py +0 -0
  53. {safeuploads-1.1.2 → safeuploads-1.1.3}/safeuploads/exceptions.py +0 -0
  54. {safeuploads-1.1.2 → safeuploads-1.1.3}/safeuploads/file_validator.py +0 -0
  55. {safeuploads-1.1.2 → safeuploads-1.1.3}/safeuploads/inspectors/__init__.py +0 -0
  56. {safeuploads-1.1.2 → safeuploads-1.1.3}/safeuploads/inspectors/base.py +0 -0
  57. {safeuploads-1.1.2 → safeuploads-1.1.3}/safeuploads/inspectors/content_inspector.py +0 -0
  58. {safeuploads-1.1.2 → safeuploads-1.1.3}/safeuploads/inspectors/gzip_inspector.py +0 -0
  59. {safeuploads-1.1.2 → safeuploads-1.1.3}/safeuploads/inspectors/zip_inspector.py +0 -0
  60. {safeuploads-1.1.2 → safeuploads-1.1.3}/safeuploads/py.typed +0 -0
  61. {safeuploads-1.1.2 → safeuploads-1.1.3}/safeuploads/utils.py +0 -0
  62. {safeuploads-1.1.2 → safeuploads-1.1.3}/safeuploads/validators/__init__.py +0 -0
  63. {safeuploads-1.1.2 → safeuploads-1.1.3}/safeuploads/validators/base.py +0 -0
  64. {safeuploads-1.1.2 → safeuploads-1.1.3}/safeuploads/validators/compression_validator.py +0 -0
  65. {safeuploads-1.1.2 → safeuploads-1.1.3}/safeuploads/validators/extension_validator.py +0 -0
  66. {safeuploads-1.1.2 → safeuploads-1.1.3}/safeuploads/validators/unicode_validator.py +0 -0
  67. {safeuploads-1.1.2 → safeuploads-1.1.3}/safeuploads/validators/windows_validator.py +0 -0
  68. {safeuploads-1.1.2 → safeuploads-1.1.3}/safeuploads/validators/xml_validator.py +0 -0
  69. {safeuploads-1.1.2 → safeuploads-1.1.3}/tests/__init__.py +0 -0
  70. {safeuploads-1.1.2 → safeuploads-1.1.3}/tests/conftest.py +0 -0
  71. {safeuploads-1.1.2 → safeuploads-1.1.3}/tests/fuzz/__init__.py +0 -0
  72. {safeuploads-1.1.2 → safeuploads-1.1.3}/tests/fuzz/test_fuzz_config.py +0 -0
  73. {safeuploads-1.1.2 → safeuploads-1.1.3}/tests/fuzz/test_fuzz_filenames.py +0 -0
  74. {safeuploads-1.1.2 → safeuploads-1.1.3}/tests/fuzz/test_fuzz_images.py +0 -0
  75. {safeuploads-1.1.2 → safeuploads-1.1.3}/tests/fuzz/test_fuzz_zip.py +0 -0
  76. {safeuploads-1.1.2 → safeuploads-1.1.3}/tests/inspectors/__init__.py +0 -0
  77. {safeuploads-1.1.2 → safeuploads-1.1.3}/tests/inspectors/test_content_inspector.py +0 -0
  78. {safeuploads-1.1.2 → safeuploads-1.1.3}/tests/inspectors/test_gzip_inspector.py +0 -0
  79. {safeuploads-1.1.2 → safeuploads-1.1.3}/tests/inspectors/test_zip_inspector.py +0 -0
  80. {safeuploads-1.1.2 → safeuploads-1.1.3}/tests/test_audit.py +0 -0
  81. {safeuploads-1.1.2 → safeuploads-1.1.3}/tests/test_config.py +0 -0
  82. {safeuploads-1.1.2 → safeuploads-1.1.3}/tests/test_config_validation.py +0 -0
  83. {safeuploads-1.1.2 → safeuploads-1.1.3}/tests/test_enums.py +0 -0
  84. {safeuploads-1.1.2 → safeuploads-1.1.3}/tests/test_exceptions.py +0 -0
  85. {safeuploads-1.1.2 → safeuploads-1.1.3}/tests/test_fastapi_integration.py +0 -0
  86. {safeuploads-1.1.2 → safeuploads-1.1.3}/tests/test_file_validator.py +0 -0
  87. {safeuploads-1.1.2 → safeuploads-1.1.3}/tests/test_performance.py +0 -0
  88. {safeuploads-1.1.2 → safeuploads-1.1.3}/tests/test_utils.py +0 -0
  89. {safeuploads-1.1.2 → safeuploads-1.1.3}/tests/test_validate_activity_file.py +0 -0
  90. {safeuploads-1.1.2 → safeuploads-1.1.3}/tests/test_validate_gzip_file.py +0 -0
  91. {safeuploads-1.1.2 → safeuploads-1.1.3}/tests/validators/__init__.py +0 -0
  92. {safeuploads-1.1.2 → safeuploads-1.1.3}/tests/validators/test_compression_validator.py +0 -0
  93. {safeuploads-1.1.2 → safeuploads-1.1.3}/tests/validators/test_extension_validator.py +0 -0
  94. {safeuploads-1.1.2 → safeuploads-1.1.3}/tests/validators/test_unicode_validator.py +0 -0
  95. {safeuploads-1.1.2 → safeuploads-1.1.3}/tests/validators/test_windows_validator.py +0 -0
  96. {safeuploads-1.1.2 → safeuploads-1.1.3}/tests/validators/test_xml_validator.py +0 -0
@@ -50,6 +50,34 @@ jobs:
50
50
  - name: Type check with mypy
51
51
  run: uv run mypy
52
52
 
53
+ # ----------------------------------------------------------------
54
+ # Type check with ty (advisory)
55
+ # ty is pre-1.0 and runs beside mypy for evaluation: findings are
56
+ # reported but never block a merge. mypy is the gate.
57
+ # ----------------------------------------------------------------
58
+ typecheck-ty:
59
+ name: Type check (ty, advisory)
60
+ runs-on: ubuntu-latest
61
+ continue-on-error: true
62
+
63
+ steps:
64
+ - name: Checkout code
65
+ uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
66
+ with:
67
+ fetch-depth: 1
68
+
69
+ - name: Install uv
70
+ uses: astral-sh/setup-uv@18d369b23da25a81e9458561248e1aafff6a70fa # v10.3.1
71
+ with:
72
+ version-file: pyproject.toml
73
+
74
+ - name: Install dependencies
75
+ # Same environment as the mypy step: ty resolves third-party types from it.
76
+ run: uv sync --frozen --dev --extra fastapi
77
+
78
+ - name: Type check (ty)
79
+ run: uv run --no-sync ty check --python .venv
80
+
53
81
  # ----------------------------------------------------------------
54
82
  # Test
55
83
  # Runs the full pytest suite with coverage. Only runs after lint
@@ -4,6 +4,14 @@ All notable changes to this project are documented in this file.
4
4
 
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
6
 
7
+ ## [1.1.3] - 2026-10-22
8
+
9
+ ### Changed
10
+
11
+ - Development: the Astral `ty` type checker runs beside mypy as an advisory CI job (`Type check (ty, advisory)`); mypy remains the gate.
12
+ - `SeekableFile.read` and `seek` take positional-only parameters, so `BytesIO` and `SpooledTemporaryFile` satisfy the protocol under `ty`. No runtime change.
13
+ - `UploadFileProtocol.seek` may return `int | None`, so FastAPI/Starlette's `UploadFile` (whose `seek` returns `None`) satisfies the protocol under strict type checking. No runtime change.
14
+
7
15
  ## [1.1.2] - 2026-10-22
8
16
 
9
17
  ### Changed
@@ -104,6 +112,7 @@ Initial release.
104
112
  - **MIME type verification:** magic-number validation for common file types.
105
113
  - Framework-agnostic async validation, a rich exception hierarchy with machine-readable error codes, secure defaults, and full type hints.
106
114
 
115
+ [1.1.3]: https://github.com/endurain-project/safeuploads/compare/v1.1.2...v1.1.3
107
116
  [1.1.2]: https://github.com/endurain-project/safeuploads/compare/v1.1.1...v1.1.2
108
117
  [1.1.1]: https://github.com/endurain-project/safeuploads/compare/v1.1.0...v1.1.1
109
118
  [1.1.0]: https://github.com/endurain-project/safeuploads/compare/v1.0.1...v1.1.0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: safeuploads
3
- Version: 1.1.2
3
+ Version: 1.1.3
4
4
  Summary: A comprehensive file security system for validating uploads and preventing attacks
5
5
  Author-email: João Vitória Silva <joao@endurain.com>
6
6
  License: MIT
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "safeuploads"
3
- version = "1.1.2"
3
+ version = "1.1.3"
4
4
  description = "A comprehensive file security system for validating uploads and preventing attacks"
5
5
  authors = [
6
6
  {name = "João Vitória Silva",email = "joao@endurain.com"}
@@ -24,6 +24,7 @@ dev = [
24
24
  "ruff>=0.9.0",
25
25
  "hypothesis>=6.100,<7.0",
26
26
  "mypy>=1.20.2",
27
+ "ty>=0.0.83",
27
28
  "types-defusedxml",
28
29
  # HTTP stack for the FastAPI multipart integration test
29
30
  "httpx>=0.27,<1.0",
@@ -165,3 +166,11 @@ exclude = ["tests/"]
165
166
  [[tool.mypy.overrides]]
166
167
  module = ["magic", "fastapi"]
167
168
  ignore_missing_imports = true
169
+
170
+ # ``ty`` runs beside mypy as an advisory, non-blocking CI job (it is pre-1.0);
171
+ # mypy stays the gate. Same scope as ``[tool.mypy]``.
172
+ [tool.ty.environment]
173
+ python-version = "3.13"
174
+
175
+ [tool.ty.src]
176
+ include = ["safeuploads"]
@@ -23,7 +23,7 @@ class SeekableFile(Protocol):
23
23
  tell: Return current file pointer position.
24
24
  """
25
25
 
26
- def read(self, size: int = -1) -> bytes:
26
+ def read(self, size: int = -1, /) -> bytes:
27
27
  """
28
28
  Read bytes from the file.
29
29
 
@@ -35,7 +35,7 @@ class SeekableFile(Protocol):
35
35
  """
36
36
  ... # pragma: no cover
37
37
 
38
- def seek(self, offset: int, whence: int = 0) -> int:
38
+ def seek(self, offset: int, whence: int = 0, /) -> int:
39
39
  """
40
40
  Move file pointer to specified position.
41
41
 
@@ -76,7 +76,7 @@ class UploadFileProtocol(Protocol):
76
76
  filename: str | None
77
77
  size: int | None
78
78
 
79
- async def read(self, size: int = -1) -> bytes:
79
+ async def read(self, size: int = -1, /) -> bytes:
80
80
  """
81
81
  Read bytes from the uploaded file.
82
82
 
@@ -88,7 +88,7 @@ class UploadFileProtocol(Protocol):
88
88
  """
89
89
  ... # pragma: no cover
90
90
 
91
- async def seek(self, offset: int) -> int:
91
+ async def seek(self, offset: int) -> int | None:
92
92
  """
93
93
  Move file pointer to specified position.
94
94
 
@@ -96,6 +96,7 @@ class UploadFileProtocol(Protocol):
96
96
  offset: Position to move to in bytes.
97
97
 
98
98
  Returns:
99
- New position in the file.
99
+ New position in the file, or None for implementations
100
+ (such as Starlette's UploadFile) that return nothing.
100
101
  """
101
102
  ... # pragma: no cover
@@ -1163,7 +1163,7 @@ wheels = [
1163
1163
 
1164
1164
  [[package]]
1165
1165
  name = "safeuploads"
1166
- version = "1.1.2"
1166
+ version = "1.1.3"
1167
1167
  source = { editable = "." }
1168
1168
  dependencies = [
1169
1169
  { name = "defusedxml" },
@@ -1185,6 +1185,7 @@ dev = [
1185
1185
  { name = "pytest-cov" },
1186
1186
  { name = "python-multipart" },
1187
1187
  { name = "ruff" },
1188
+ { name = "ty" },
1188
1189
  { name = "types-defusedxml" },
1189
1190
  ]
1190
1191
  docs = [
@@ -1210,6 +1211,7 @@ dev = [
1210
1211
  { name = "pytest-cov", specifier = ">=4.1,<8.0" },
1211
1212
  { name = "python-multipart", specifier = ">=0.0.9,<1.0" },
1212
1213
  { name = "ruff", specifier = ">=0.9.0" },
1214
+ { name = "ty", specifier = ">=0.0.83" },
1213
1215
  { name = "types-defusedxml" },
1214
1216
  ]
1215
1217
  docs = [
@@ -1247,6 +1249,31 @@ wheels = [
1247
1249
  { url = "https://files.pythonhosted.org/packages/c8/cb/6a6a47d5b464bd08695d254f3da6e7986cc70c9fa5d778eda57538edfe56/starlette-1.6.0-py3-none-any.whl", hash = "sha256:a86dd39d14bb45f85a3d18525215a9ef0cfd1f192ac793220e72598c90335f0c", size = 75969, upload-time = "2026-08-08T18:27:56.196Z" },
1248
1250
  ]
1249
1251
 
1252
+ [[package]]
1253
+ name = "ty"
1254
+ version = "0.0.83"
1255
+ source = { registry = "https://pypi.org/simple" }
1256
+ sdist = { url = "https://files.pythonhosted.org/packages/3b/7d/2fd9575bce2d14e2281bec82d0713dee68329b0dc944e9c06c2e36b761fe/ty-0.0.83.tar.gz", hash = "sha256:db118de73c05ac476faceb4d42d59782feaeddfc4d721fd3ae8b807a0a2ae4e4", size = 7373076, upload-time = "2026-09-21T22:47:29.207Z" }
1257
+ wheels = [
1258
+ { url = "https://files.pythonhosted.org/packages/bf/85/7259431bade2317d8b82fa27220ae4618c21396acf0ca28a7bd75e92afd7/ty-0.0.83-py3-none-linux_armv6l.whl", hash = "sha256:836bc08bad96ecc7e38baf1a6ddaec15aa8c8b46ae99a96365397b5f6481b7a5", size = 13905669, upload-time = "2026-09-21T22:46:36.677Z" },
1259
+ { url = "https://files.pythonhosted.org/packages/d2/30/9527386ade8dd71fc52f65cde3c094411af7ad0d505f9063ef0841998702/ty-0.0.83-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:0f1fb029fe076c7dca404d98e38fdb5fdbc2038a09407f89d43be1fdd9b2c459", size = 13499505, upload-time = "2026-09-21T22:46:40.114Z" },
1260
+ { url = "https://files.pythonhosted.org/packages/a0/54/63080d8cfd59a53810499a69a2ebc995724be27618b70d7f099e73ace317/ty-0.0.83-py3-none-macosx_11_0_arm64.whl", hash = "sha256:3515776d01ee3b1be974dafa73d449d0bc711afbc12ba341f82f70bc641ff4ee", size = 13498980, upload-time = "2026-09-21T22:46:43.197Z" },
1261
+ { url = "https://files.pythonhosted.org/packages/49/78/e647f190bd9513d09db30d45309e9b5df070b5caa44af2de3290fab59fbe/ty-0.0.83-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c5b80d66c7f9c8d60f25ccfd40c6eaebe8fd7c9005074904e0e164dd89c13d03", size = 13494705, upload-time = "2026-09-21T22:46:46.106Z" },
1262
+ { url = "https://files.pythonhosted.org/packages/2e/12/aef645b13c5bd15e3e5993537dbc23f7d65475f3cf1755d07b4d3e56850d/ty-0.0.83-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:57eae4aa55dab1af5d1423227c6517ccab1e658fe265c8e5a58caa584ca2876b", size = 13661466, upload-time = "2026-09-21T22:46:49.392Z" },
1263
+ { url = "https://files.pythonhosted.org/packages/d4/c4/11872e823653c568468ef7f0c3b23aed7ad2d33652e20144d28d5bfad58a/ty-0.0.83-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dea3680911340ecf93dff5786dbeefd69c9399df685a22751e1fbd27e6007b50", size = 14479677, upload-time = "2026-09-21T22:46:52.277Z" },
1264
+ { url = "https://files.pythonhosted.org/packages/8e/db/5b0d0d24d16d24d781f29ee842ee718903e453dc4068acb02bef860d5540/ty-0.0.83-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8453786c274f48e2a89b78e8a505a4f449323f357f2ce26a9b90a4bd68176f67", size = 14972208, upload-time = "2026-09-21T22:46:55.242Z" },
1265
+ { url = "https://files.pythonhosted.org/packages/54/04/0077a53bcf6ceb41365a45d8091b52094c91a5f4b071c2a6d705ed8bb65b/ty-0.0.83-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7701bdae3b52271cf0835abe4202aa3b23b735425d8c5a3e6a8ca1c68d39ead8", size = 14660550, upload-time = "2026-09-21T22:46:58.256Z" },
1266
+ { url = "https://files.pythonhosted.org/packages/d4/ff/b6c879f1c3121387edd19ebdb1fb02af30691f88f632278a5d467fb5f348/ty-0.0.83-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aa95b4376447e5309fe3ccc98ee75916a9082714e6a029b99427ca62021dc94a", size = 14147376, upload-time = "2026-09-21T22:47:01.167Z" },
1267
+ { url = "https://files.pythonhosted.org/packages/0d/bc/82e730247d53cb02acd5a91237c0c62f215b2e0379689a550176d307ed89/ty-0.0.83-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:2a4550a08fc1899a33e4a08787a73ec9daa99d292268df4f0a5f1c24c63854c3", size = 14567502, upload-time = "2026-09-21T22:47:04.344Z" },
1268
+ { url = "https://files.pythonhosted.org/packages/67/13/bb6f57923231f51b626931625ada71e219d64541f8fadf96065bc5034358/ty-0.0.83-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:feb72080f0835fa2b27485e3b11fa50dc57c30e0ba73808a3f7d64b56db83f6f", size = 13443051, upload-time = "2026-09-21T22:47:07.316Z" },
1269
+ { url = "https://files.pythonhosted.org/packages/50/20/9862431662d4453527cd52cf0f30d5975cd1801aa39e570bf45fb299be77/ty-0.0.83-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:3e5206def2d6e1df93c75ed8dc763255233ccc3153647509d125bada10ad770a", size = 13678908, upload-time = "2026-09-21T22:47:10.714Z" },
1270
+ { url = "https://files.pythonhosted.org/packages/d7/e3/94ebbe1573b76660fa09f2dbce96da6d0bb69a2d29c7b6ad538b452979d4/ty-0.0.83-py3-none-musllinux_1_2_i686.whl", hash = "sha256:bdf5dfa157f5c127ba096fe0561b47877e6e79562c7fc2b35906ba5e9f6bb723", size = 13937248, upload-time = "2026-09-21T22:47:14.133Z" },
1271
+ { url = "https://files.pythonhosted.org/packages/2f/c0/3ea45c2ec3a82fddb7137e457ccb2a452446905430d225adaa4990cdc338/ty-0.0.83-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:626d6ad00f05a5d9b7ea80de44b12931d0c0fb50e64eab20b7fcc13e9aff2a68", size = 14290826, upload-time = "2026-09-21T22:47:16.874Z" },
1272
+ { url = "https://files.pythonhosted.org/packages/d8/b2/c941ce83a59e46ef31dd04bdf6067530e7ec77d5f0cdd1e223fbc6fc351b/ty-0.0.83-py3-none-win32.whl", hash = "sha256:0391017dac6ba3e452e0322301f50bba12fbccadac07d7fd888c46951ad37638", size = 13105291, upload-time = "2026-09-21T22:47:19.807Z" },
1273
+ { url = "https://files.pythonhosted.org/packages/b2/8a/5eef9458505698b144643cbd2062f465c5d860d8cf86a8710d74505ad9a0/ty-0.0.83-py3-none-win_amd64.whl", hash = "sha256:1b67d86f5bbad4076ae1a2ff23a6a4493219885d72d4b148cb0193e090390060", size = 13901557, upload-time = "2026-09-21T22:47:23.429Z" },
1274
+ { url = "https://files.pythonhosted.org/packages/9f/27/a06061513f1de25569c2e8898018bd552ab7b31afa7cfe818703269b3350/ty-0.0.83-py3-none-win_arm64.whl", hash = "sha256:a916a3d7d68fe30b7aacdb9fe16d461fa944d722e59e96ea0fa9d206a1b6625f", size = 13627960, upload-time = "2026-09-21T22:47:26.305Z" },
1275
+ ]
1276
+
1250
1277
  [[package]]
1251
1278
  name = "types-defusedxml"
1252
1279
  version = "0.7.0.20260504"
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes