pypi-sdk 1.0.0__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.
- pypi_sdk-1.0.0/.github/workflows/ci.yml +40 -0
- pypi_sdk-1.0.0/.github/workflows/publish.yml +64 -0
- pypi_sdk-1.0.0/AGENTS.MD +39 -0
- pypi_sdk-1.0.0/CHANGELOG.md +23 -0
- pypi_sdk-1.0.0/CLAUDE.md +14 -0
- pypi_sdk-1.0.0/CODE_OF_CONDUCT.md +14 -0
- pypi_sdk-1.0.0/CONTRIBUTING.md +77 -0
- pypi_sdk-1.0.0/LICENSE.md +21 -0
- pypi_sdk-1.0.0/PKG-INFO +190 -0
- pypi_sdk-1.0.0/README.md +167 -0
- pypi_sdk-1.0.0/SECURITY.md +27 -0
- pypi_sdk-1.0.0/benchmarks/benchcore_cases.py +51 -0
- pypi_sdk-1.0.0/benchmarks/test_models.py +41 -0
- pypi_sdk-1.0.0/docs/api.md +52 -0
- pypi_sdk-1.0.0/docs/architecture.md +24 -0
- pypi_sdk-1.0.0/docs/changelog.md +4 -0
- pypi_sdk-1.0.0/docs/compatibility.md +31 -0
- pypi_sdk-1.0.0/docs/configuration.md +25 -0
- pypi_sdk-1.0.0/docs/development.md +41 -0
- pypi_sdk-1.0.0/docs/errors.md +20 -0
- pypi_sdk-1.0.0/docs/index.md +27 -0
- pypi_sdk-1.0.0/docs/publishing.md +67 -0
- pypi_sdk-1.0.0/docs/quickstart.md +64 -0
- pypi_sdk-1.0.0/docs/releasing.md +26 -0
- pypi_sdk-1.0.0/docs/roadmap.md +21 -0
- pypi_sdk-1.0.0/examples/publish.yml +47 -0
- pypi_sdk-1.0.0/mkdocs.yml +38 -0
- pypi_sdk-1.0.0/pyproject.toml +106 -0
- pypi_sdk-1.0.0/pyproject.toml.orig +94 -0
- pypi_sdk-1.0.0/src/pypi_sdk/__init__.py +62 -0
- pypi_sdk-1.0.0/src/pypi_sdk/cli.py +48 -0
- pypi_sdk-1.0.0/src/pypi_sdk/client.py +151 -0
- pypi_sdk-1.0.0/src/pypi_sdk/config.py +42 -0
- pypi_sdk-1.0.0/src/pypi_sdk/constants.py +7 -0
- pypi_sdk-1.0.0/src/pypi_sdk/errors.py +50 -0
- pypi_sdk-1.0.0/src/pypi_sdk/models.py +97 -0
- pypi_sdk-1.0.0/src/pypi_sdk/publish.py +79 -0
- pypi_sdk-1.0.0/src/pypi_sdk/py.typed +0 -0
- pypi_sdk-1.0.0/src/pypi_sdk/services.py +143 -0
- pypi_sdk-1.0.0/tests/test_api.py +299 -0
- pypi_sdk-1.0.0/tests/test_cli.py +70 -0
- pypi_sdk-1.0.0/tests/test_publish.py +62 -0
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
pull_request:
|
|
6
|
+
|
|
7
|
+
permissions:
|
|
8
|
+
contents: read
|
|
9
|
+
|
|
10
|
+
jobs:
|
|
11
|
+
checks:
|
|
12
|
+
runs-on: ubuntu-latest
|
|
13
|
+
strategy:
|
|
14
|
+
fail-fast: false
|
|
15
|
+
matrix:
|
|
16
|
+
python-version: ["3.11", "3.12", "3.13", "3.14"]
|
|
17
|
+
steps:
|
|
18
|
+
- uses: actions/checkout@v4
|
|
19
|
+
- uses: actions/setup-python@v5
|
|
20
|
+
with:
|
|
21
|
+
python-version: ${{ matrix.python-version }}
|
|
22
|
+
- uses: astral-sh/setup-uv@v6
|
|
23
|
+
with:
|
|
24
|
+
enable-cache: true
|
|
25
|
+
- name: Install locked development dependencies
|
|
26
|
+
run: uv sync --locked --group dev --group docs
|
|
27
|
+
- name: Check formatting and lint
|
|
28
|
+
run: |
|
|
29
|
+
uv run ruff check .
|
|
30
|
+
uv run ruff format --check .
|
|
31
|
+
- name: Check types
|
|
32
|
+
run: |
|
|
33
|
+
uv run mypy src
|
|
34
|
+
uv run basedpyright
|
|
35
|
+
- name: Run tests
|
|
36
|
+
run: uv run pytest
|
|
37
|
+
- name: Build documentation
|
|
38
|
+
run: uv run mkdocs build --strict
|
|
39
|
+
- name: Build distributions
|
|
40
|
+
run: uv build
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
name: Publish to PyPI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
release:
|
|
5
|
+
types: [published]
|
|
6
|
+
workflow_dispatch:
|
|
7
|
+
|
|
8
|
+
permissions:
|
|
9
|
+
contents: read
|
|
10
|
+
|
|
11
|
+
jobs:
|
|
12
|
+
build:
|
|
13
|
+
if: startsWith(github.ref, 'refs/tags/v')
|
|
14
|
+
name: Build and validate distributions
|
|
15
|
+
runs-on: ubuntu-latest
|
|
16
|
+
steps:
|
|
17
|
+
- uses: actions/checkout@v7
|
|
18
|
+
- uses: actions/setup-python@v7
|
|
19
|
+
with:
|
|
20
|
+
python-version: "3.12"
|
|
21
|
+
- uses: astral-sh/setup-uv@v6
|
|
22
|
+
with:
|
|
23
|
+
enable-cache: true
|
|
24
|
+
- name: Build distributions
|
|
25
|
+
run: uv build
|
|
26
|
+
- name: Validate built wheel
|
|
27
|
+
run: |
|
|
28
|
+
python -m pip install dist/*.whl
|
|
29
|
+
python - <<'PY'
|
|
30
|
+
import os
|
|
31
|
+
from importlib.metadata import version
|
|
32
|
+
|
|
33
|
+
import pypi_sdk
|
|
34
|
+
|
|
35
|
+
package_version = version("pypi-sdk")
|
|
36
|
+
tag_version = os.environ["GITHUB_REF_NAME"].removeprefix("v")
|
|
37
|
+
assert pypi_sdk.__version__ == package_version == tag_version
|
|
38
|
+
print(package_version)
|
|
39
|
+
PY
|
|
40
|
+
- name: Store distributions
|
|
41
|
+
uses: actions/upload-artifact@v7
|
|
42
|
+
with:
|
|
43
|
+
name: python-package-distributions
|
|
44
|
+
path: dist/
|
|
45
|
+
if-no-files-found: error
|
|
46
|
+
|
|
47
|
+
publish:
|
|
48
|
+
if: startsWith(github.ref, 'refs/tags/v')
|
|
49
|
+
name: Publish distribution to PyPI
|
|
50
|
+
needs: build
|
|
51
|
+
runs-on: ubuntu-latest
|
|
52
|
+
environment:
|
|
53
|
+
name: pypi
|
|
54
|
+
url: https://pypi.org/project/pypi-sdk/
|
|
55
|
+
permissions:
|
|
56
|
+
id-token: write
|
|
57
|
+
steps:
|
|
58
|
+
- name: Download distributions
|
|
59
|
+
uses: actions/download-artifact@v8
|
|
60
|
+
with:
|
|
61
|
+
name: python-package-distributions
|
|
62
|
+
path: dist/
|
|
63
|
+
- name: Publish to PyPI
|
|
64
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
pypi_sdk-1.0.0/AGENTS.MD
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# Repository Instructions for Coding Agents
|
|
2
|
+
|
|
3
|
+
## Project
|
|
4
|
+
|
|
5
|
+
This repository builds `pypi-sdk`, an unofficial typed Python client for PyPI's
|
|
6
|
+
documented APIs. Python imports use `pypi_sdk`. Code, docs, examples, benchmark
|
|
7
|
+
names, and commit messages are in English; communicate with the user in their
|
|
8
|
+
preferred language.
|
|
9
|
+
|
|
10
|
+
## Boundaries
|
|
11
|
+
|
|
12
|
+
- Keep the client synchronous and use the shared HTTPX client.
|
|
13
|
+
- Model documented API responses with Pydantic v2, preserving additive fields.
|
|
14
|
+
- Do not add account-management endpoints PyPI does not document as public APIs.
|
|
15
|
+
- Do not wrap deprecated XML-RPC, partner-only secret reporting, or BigQuery as
|
|
16
|
+
PyPI HTTP endpoints.
|
|
17
|
+
- Publishing uploads built artifacts through Twine. Do not rebuild its upload
|
|
18
|
+
protocol or claim that an existing release can be overwritten.
|
|
19
|
+
- Keep credentials explicit, out of logs/arguments, and scoped to upload.
|
|
20
|
+
- Avoid automatic retries, redirects, or network access in normal tests.
|
|
21
|
+
|
|
22
|
+
## Validation
|
|
23
|
+
|
|
24
|
+
Use the workspace `.venv` and locked uv dependencies. Before committing, run:
|
|
25
|
+
|
|
26
|
+
```console
|
|
27
|
+
uv run ruff check .
|
|
28
|
+
uv run ruff format --check .
|
|
29
|
+
uv run mypy src
|
|
30
|
+
uv run basedpyright
|
|
31
|
+
uv run pytest
|
|
32
|
+
uv run --group docs mkdocs build --strict
|
|
33
|
+
uv build
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
BenchCore is optional and requires Python 3.12+. Never commit benchmark output.
|
|
37
|
+
Read `CONTRIBUTING.md`, `SECURITY.md`, and the `docs/` pages for release and
|
|
38
|
+
security requirements. Preserve unrelated work and do not claim remote
|
|
39
|
+
publication when only local commits or tags exist.
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
User-visible changes are recorded here. This project follows semantic
|
|
4
|
+
versioning; compatibility changes are called out explicitly.
|
|
5
|
+
|
|
6
|
+
## 1.0.0
|
|
7
|
+
|
|
8
|
+
### Added
|
|
9
|
+
|
|
10
|
+
- Typed synchronous clients for PyPI project/release JSON, the PEP 691 JSON
|
|
11
|
+
Simple Index, PEP 740 provenance, storage statistics, and RSS feeds.
|
|
12
|
+
- Optional Twine-backed publishing to PyPI or TestPyPI, plus a GitHub Actions
|
|
13
|
+
Trusted Publishing example.
|
|
14
|
+
- Python 3.11+ support, strict BasedPyright and Mypy checks, coverage-enforced
|
|
15
|
+
tests, pytest-benchmark, and optional BenchCore measurements.
|
|
16
|
+
- English API, publishing, development, compatibility, security, and release
|
|
17
|
+
documentation.
|
|
18
|
+
|
|
19
|
+
### Changed
|
|
20
|
+
|
|
21
|
+
- Preserve the JSON and RSS fields returned by PyPI while typing stable fields.
|
|
22
|
+
- Keep account administration, the partner-only secret API, BigQuery, and
|
|
23
|
+
deprecated XML-RPC outside the HTTP SDK surface.
|
pypi_sdk-1.0.0/CLAUDE.md
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# Claude Repository Guide
|
|
2
|
+
|
|
3
|
+
Read and follow [AGENTS.MD](AGENTS.MD), the canonical repository instructions.
|
|
4
|
+
Keep shared project rules there so this guide does not drift.
|
|
5
|
+
|
|
6
|
+
The distribution is `pypi-sdk`; the import package is `pypi_sdk`. This is an
|
|
7
|
+
unofficial synchronous client for PyPI's documented public APIs. The supported
|
|
8
|
+
surface and release boundaries are documented in `docs/api.md` and
|
|
9
|
+
`docs/compatibility.md`.
|
|
10
|
+
|
|
11
|
+
Use the workspace `.venv` and locked uv dependencies. Run the validation commands
|
|
12
|
+
from `AGENTS.MD`. Optional BenchCore runs only on Python 3.12+. Keep source,
|
|
13
|
+
documentation, and commit messages in English; answer the user in their preferred
|
|
14
|
+
language. Report only checks and releases actually completed.
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# Code of Conduct
|
|
2
|
+
|
|
3
|
+
We welcome contributors with different backgrounds and experience levels. Be
|
|
4
|
+
respectful, explain technical disagreements constructively, and give others
|
|
5
|
+
room to learn.
|
|
6
|
+
|
|
7
|
+
Harassment, threats, discrimination, unwanted personal attention, and
|
|
8
|
+
publication of private information are not acceptable in project issues,
|
|
9
|
+
pull requests, reviews, or other project spaces.
|
|
10
|
+
|
|
11
|
+
Report concerns privately to the maintainer at
|
|
12
|
+
ramirez.ruiz.eliezer.reuven@gmail.com. Reports will be handled with care for the
|
|
13
|
+
privacy of those involved. The maintainer may remove harmful content or limit
|
|
14
|
+
participation to protect the community.
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
# Contributing
|
|
2
|
+
|
|
3
|
+
Thanks for helping improve this unofficial PyPI SDK. Keep source code,
|
|
4
|
+
documentation, examples, and commit messages in English.
|
|
5
|
+
|
|
6
|
+
## Development setup
|
|
7
|
+
|
|
8
|
+
Install Python 3.11+ and uv, then create the locked development environment:
|
|
9
|
+
|
|
10
|
+
```console
|
|
11
|
+
uv sync --locked --group dev --group docs
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
Runtime dependencies belong in `[project.dependencies]`. Keep test, docs,
|
|
15
|
+
benchmark, and publishing tools in their corresponding optional groups. Update
|
|
16
|
+
`uv.lock` with uv; do not edit it by hand.
|
|
17
|
+
|
|
18
|
+
## Validation
|
|
19
|
+
|
|
20
|
+
Run the full offline checks before committing:
|
|
21
|
+
|
|
22
|
+
```console
|
|
23
|
+
uv run ruff check .
|
|
24
|
+
uv run ruff format --check .
|
|
25
|
+
uv run mypy src
|
|
26
|
+
uv run basedpyright
|
|
27
|
+
uv run pytest
|
|
28
|
+
uv run --group docs mkdocs build --strict
|
|
29
|
+
uv build
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
Tests use HTTPX `MockTransport`; normal test runs do not contact PyPI or upload
|
|
33
|
+
files. Never test a write against production. Keep tests focused on observable
|
|
34
|
+
behavior and cover credential-sensitive code without real credentials.
|
|
35
|
+
|
|
36
|
+
Optional performance checks are opt-in:
|
|
37
|
+
|
|
38
|
+
```console
|
|
39
|
+
uv run --group benchmark pytest benchmarks --no-cov --benchmark-only
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
BenchCore requires Python 3.12+:
|
|
43
|
+
|
|
44
|
+
```console
|
|
45
|
+
uv run --group benchcore pytest benchmarks/benchcore_cases.py --no-cov --benchcore-save=.benchcore
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Benchmark results are local artifacts and should not be committed.
|
|
49
|
+
|
|
50
|
+
## Changes and commits
|
|
51
|
+
|
|
52
|
+
Keep changes cohesive, preserve unrelated work, and use Conventional Commits,
|
|
53
|
+
for example:
|
|
54
|
+
|
|
55
|
+
```text
|
|
56
|
+
feat(api): add release metadata lookup
|
|
57
|
+
fix(publish): reject missing distributions
|
|
58
|
+
docs(publishing): explain Trusted Publishing
|
|
59
|
+
chore(release): prepare 1.0.0
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
Update the changelog and directly related docs for user-visible changes. Do not
|
|
63
|
+
create a version tag until the version in `pyproject.toml`, package constants,
|
|
64
|
+
and release notes agree and the validation above passes. Tags are release
|
|
65
|
+
markers, not placeholders for future versions.
|
|
66
|
+
|
|
67
|
+
Commits created by Copilot include this trailer:
|
|
68
|
+
|
|
69
|
+
```text
|
|
70
|
+
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
## Publishing
|
|
74
|
+
|
|
75
|
+
Use the repository release workflow and PyPI Trusted Publishing once a remote
|
|
76
|
+
and trusted publisher are configured. Do not put long-lived PyPI tokens in
|
|
77
|
+
workflow files or command-line arguments. Test releases on TestPyPI first.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Eli-ezer Reuven Ramirez Ruiz
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
pypi_sdk-1.0.0/PKG-INFO
ADDED
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: pypi-sdk
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Typed Python client for PyPI's public APIs and package publishing
|
|
5
|
+
Keywords: pypi,python-packaging,sdk,publishing
|
|
6
|
+
Author: Eli-ezer Reuven Ramirez Ruiz
|
|
7
|
+
Author-email: Eli-ezer Reuven Ramirez Ruiz <ramirez.ruiz.eliezer.reuven@gmail.com>
|
|
8
|
+
License-Expression: MIT
|
|
9
|
+
License-File: LICENSE.md
|
|
10
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
11
|
+
Classifier: Programming Language :: Python :: 3
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
16
|
+
Classifier: Typing :: Typed
|
|
17
|
+
Requires-Dist: httpx>=0.28.1
|
|
18
|
+
Requires-Dist: pydantic>=2.12.0,<3
|
|
19
|
+
Requires-Dist: twine>=6.0 ; extra == 'publish'
|
|
20
|
+
Requires-Python: >=3.11
|
|
21
|
+
Provides-Extra: publish
|
|
22
|
+
Description-Content-Type: text/markdown
|
|
23
|
+
|
|
24
|
+
# PyPI SDK
|
|
25
|
+
|
|
26
|
+
An unofficial, typed Python SDK for PyPI's documented public APIs. It provides
|
|
27
|
+
one synchronous client for package metadata, the PEP 691 index, provenance,
|
|
28
|
+
statistics, RSS feeds, and a Twine-backed distribution publisher.
|
|
29
|
+
|
|
30
|
+
The SDK requires Python 3.11 or later. It is not affiliated with or endorsed by
|
|
31
|
+
the Python Software Foundation or the PyPI maintainers.
|
|
32
|
+
|
|
33
|
+
## What this SDK covers
|
|
34
|
+
|
|
35
|
+
| PyPI feature | SDK interface |
|
|
36
|
+
| --- | --- |
|
|
37
|
+
| Project and release JSON | `client.projects.get()` / `get_release()` |
|
|
38
|
+
| PEP 691 JSON Simple Index | `client.index.list_projects()` / `get_project()` |
|
|
39
|
+
| PEP 740 file provenance | `client.integrity.get_provenance()` |
|
|
40
|
+
| Package storage statistics | `client.stats.get()` |
|
|
41
|
+
| New package and release RSS feeds | `client.feeds` |
|
|
42
|
+
| Legacy upload endpoint | `client.publisher.upload()` via Twine |
|
|
43
|
+
|
|
44
|
+
It intentionally does not wrap the deprecated XML-RPC API, the partner-only
|
|
45
|
+
secret reporting API, or Google BigQuery datasets as if they were normal PyPI
|
|
46
|
+
HTTP endpoints. PyPI also does not provide a public general-purpose REST API to
|
|
47
|
+
manage accounts, collaborators, or edit an existing release. Add a new version
|
|
48
|
+
to publish an update; an existing release cannot be overwritten.
|
|
49
|
+
|
|
50
|
+
## Installation
|
|
51
|
+
|
|
52
|
+
Python 3.11 or later is required. From this checkout:
|
|
53
|
+
|
|
54
|
+
```console
|
|
55
|
+
uv sync --group dev --group docs
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
After publishing, install the SDK from PyPI:
|
|
59
|
+
|
|
60
|
+
```console
|
|
61
|
+
python -m pip install pypi-sdk
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
For uploads, install the optional Twine dependency:
|
|
65
|
+
|
|
66
|
+
```console
|
|
67
|
+
python -m pip install "pypi-sdk[publish]"
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## Quick start
|
|
71
|
+
|
|
72
|
+
```python
|
|
73
|
+
from pypi_sdk import PypiClient
|
|
74
|
+
|
|
75
|
+
with PypiClient() as client:
|
|
76
|
+
project = client.projects.get("sampleproject")
|
|
77
|
+
release = client.projects.get_release("sampleproject", project.info.version)
|
|
78
|
+
files = client.index.get_project("sampleproject").files
|
|
79
|
+
print(project.info.summary, len(files), len(release.urls))
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
Responses are Pydantic models that preserve additional fields returned by PyPI.
|
|
83
|
+
The client uses anonymous GET requests by default, follows no redirects, and
|
|
84
|
+
does not retry automatically.
|
|
85
|
+
|
|
86
|
+
## Publish built distributions
|
|
87
|
+
|
|
88
|
+
Build and validate artifacts with the standard Python packaging tools, then
|
|
89
|
+
explicitly choose TestPyPI or PyPI. TestPyPI is a separate service, useful for
|
|
90
|
+
testing the release process before publishing to production.
|
|
91
|
+
|
|
92
|
+
```python
|
|
93
|
+
from pathlib import Path
|
|
94
|
+
|
|
95
|
+
from pypi_sdk import PypiClient
|
|
96
|
+
|
|
97
|
+
artifacts = Path("dist").glob("*")
|
|
98
|
+
with PypiClient() as client:
|
|
99
|
+
result = client.publisher.upload(artifacts, repository="testpypi")
|
|
100
|
+
print(result.files)
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
Twine reads `TWINE_USERNAME` and `TWINE_PASSWORD` from the environment, or can
|
|
104
|
+
receive a token explicitly without placing it in process arguments:
|
|
105
|
+
|
|
106
|
+
```python
|
|
107
|
+
import os
|
|
108
|
+
from pathlib import Path
|
|
109
|
+
|
|
110
|
+
from pypi_sdk import PypiClient
|
|
111
|
+
|
|
112
|
+
token = os.environ["PYPI_API_TOKEN"]
|
|
113
|
+
with PypiClient() as client:
|
|
114
|
+
client.publisher.upload(
|
|
115
|
+
Path("dist").glob("*"),
|
|
116
|
+
repository="pypi",
|
|
117
|
+
token=token,
|
|
118
|
+
)
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
The equivalent CLI command is:
|
|
122
|
+
|
|
123
|
+
```console
|
|
124
|
+
pypi-sdk upload --repository testpypi dist\your_package-1.0.0-py3-none-any.whl
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
The publisher delegates metadata handling and the upload protocol to Twine.
|
|
128
|
+
It does not build distributions; use `python -m build` or your project's
|
|
129
|
+
existing build backend first.
|
|
130
|
+
|
|
131
|
+
## Automated publishing with Trusted Publishing
|
|
132
|
+
|
|
133
|
+
For CI, prefer PyPI Trusted Publishing over long-lived API tokens. Configure
|
|
134
|
+
the GitHub repository and workflow as a trusted publisher in the PyPI project
|
|
135
|
+
settings using the GitHub repository owner, repository name, `publish.yml`, and
|
|
136
|
+
the `pypi` environment. Configure the matching GitHub Environment (add
|
|
137
|
+
protection rules if desired), then copy
|
|
138
|
+
[`examples/publish.yml`](examples/publish.yml) to
|
|
139
|
+
`.github/workflows/publish.yml` in the package being released. The workflow
|
|
140
|
+
builds and validates distributions, then publishes them through PyPI's official
|
|
141
|
+
GitHub Action using OIDC.
|
|
142
|
+
See the [Trusted Publishing guide](https://docs.pypi.org/trusted-publishers/).
|
|
143
|
+
|
|
144
|
+
## API policies and boundaries
|
|
145
|
+
|
|
146
|
+
- The SDK identifies itself with a `User-Agent` and honors PyPI's JSON
|
|
147
|
+
representations. The Simple Index HTML representation is not wrapped; the
|
|
148
|
+
docs recommend its JSON form for new integrations.
|
|
149
|
+
- If polling for updates, prefer RSS feeds and avoid bursts of thousands of
|
|
150
|
+
requests. The current client does not yet expose conditional ETag requests.
|
|
151
|
+
- Use the Simple Index for distribution files and verify their advertised
|
|
152
|
+
hashes after downloading.
|
|
153
|
+
- File upload creates releases one file at a time. The first file for a
|
|
154
|
+
version creates that release and fixes its metadata. To correct a release,
|
|
155
|
+
publish a new version.
|
|
156
|
+
- Project administration and Trusted Publisher setup happen in PyPI's web
|
|
157
|
+
interface; this SDK does not claim unsupported account-management endpoints.
|
|
158
|
+
|
|
159
|
+
See the [PyPI API documentation](https://docs.pypi.org/api/) and the
|
|
160
|
+
[Python Packaging User Guide](https://packaging.python.org/).
|
|
161
|
+
|
|
162
|
+
## Development
|
|
163
|
+
|
|
164
|
+
```console
|
|
165
|
+
uv sync --group dev --group docs
|
|
166
|
+
uv run ruff check .
|
|
167
|
+
uv run ruff format --check .
|
|
168
|
+
uv run mypy src
|
|
169
|
+
uv run basedpyright
|
|
170
|
+
uv run pytest
|
|
171
|
+
uv run --group docs mkdocs build --strict
|
|
172
|
+
uv build
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
Tests use mocked HTTP and do not upload packages or contact PyPI. Optional CPU
|
|
176
|
+
benchmarks are available with pytest-benchmark:
|
|
177
|
+
|
|
178
|
+
```console
|
|
179
|
+
uv run --group benchmark pytest benchmarks --no-cov --benchmark-only
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
BenchCore measurements require Python 3.12 or later:
|
|
183
|
+
|
|
184
|
+
```console
|
|
185
|
+
uv run --group benchcore pytest benchmarks/benchcore_cases.py --no-cov --benchcore-save=.benchcore
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
See [Getting started](docs/quickstart.md), [API reference](docs/api.md),
|
|
189
|
+
[publishing guide](docs/publishing.md), [development guide](docs/development.md),
|
|
190
|
+
[contributing](CONTRIBUTING.md), and the [changelog](CHANGELOG.md).
|
pypi_sdk-1.0.0/README.md
ADDED
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
# PyPI SDK
|
|
2
|
+
|
|
3
|
+
An unofficial, typed Python SDK for PyPI's documented public APIs. It provides
|
|
4
|
+
one synchronous client for package metadata, the PEP 691 index, provenance,
|
|
5
|
+
statistics, RSS feeds, and a Twine-backed distribution publisher.
|
|
6
|
+
|
|
7
|
+
The SDK requires Python 3.11 or later. It is not affiliated with or endorsed by
|
|
8
|
+
the Python Software Foundation or the PyPI maintainers.
|
|
9
|
+
|
|
10
|
+
## What this SDK covers
|
|
11
|
+
|
|
12
|
+
| PyPI feature | SDK interface |
|
|
13
|
+
| --- | --- |
|
|
14
|
+
| Project and release JSON | `client.projects.get()` / `get_release()` |
|
|
15
|
+
| PEP 691 JSON Simple Index | `client.index.list_projects()` / `get_project()` |
|
|
16
|
+
| PEP 740 file provenance | `client.integrity.get_provenance()` |
|
|
17
|
+
| Package storage statistics | `client.stats.get()` |
|
|
18
|
+
| New package and release RSS feeds | `client.feeds` |
|
|
19
|
+
| Legacy upload endpoint | `client.publisher.upload()` via Twine |
|
|
20
|
+
|
|
21
|
+
It intentionally does not wrap the deprecated XML-RPC API, the partner-only
|
|
22
|
+
secret reporting API, or Google BigQuery datasets as if they were normal PyPI
|
|
23
|
+
HTTP endpoints. PyPI also does not provide a public general-purpose REST API to
|
|
24
|
+
manage accounts, collaborators, or edit an existing release. Add a new version
|
|
25
|
+
to publish an update; an existing release cannot be overwritten.
|
|
26
|
+
|
|
27
|
+
## Installation
|
|
28
|
+
|
|
29
|
+
Python 3.11 or later is required. From this checkout:
|
|
30
|
+
|
|
31
|
+
```console
|
|
32
|
+
uv sync --group dev --group docs
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
After publishing, install the SDK from PyPI:
|
|
36
|
+
|
|
37
|
+
```console
|
|
38
|
+
python -m pip install pypi-sdk
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
For uploads, install the optional Twine dependency:
|
|
42
|
+
|
|
43
|
+
```console
|
|
44
|
+
python -m pip install "pypi-sdk[publish]"
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## Quick start
|
|
48
|
+
|
|
49
|
+
```python
|
|
50
|
+
from pypi_sdk import PypiClient
|
|
51
|
+
|
|
52
|
+
with PypiClient() as client:
|
|
53
|
+
project = client.projects.get("sampleproject")
|
|
54
|
+
release = client.projects.get_release("sampleproject", project.info.version)
|
|
55
|
+
files = client.index.get_project("sampleproject").files
|
|
56
|
+
print(project.info.summary, len(files), len(release.urls))
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Responses are Pydantic models that preserve additional fields returned by PyPI.
|
|
60
|
+
The client uses anonymous GET requests by default, follows no redirects, and
|
|
61
|
+
does not retry automatically.
|
|
62
|
+
|
|
63
|
+
## Publish built distributions
|
|
64
|
+
|
|
65
|
+
Build and validate artifacts with the standard Python packaging tools, then
|
|
66
|
+
explicitly choose TestPyPI or PyPI. TestPyPI is a separate service, useful for
|
|
67
|
+
testing the release process before publishing to production.
|
|
68
|
+
|
|
69
|
+
```python
|
|
70
|
+
from pathlib import Path
|
|
71
|
+
|
|
72
|
+
from pypi_sdk import PypiClient
|
|
73
|
+
|
|
74
|
+
artifacts = Path("dist").glob("*")
|
|
75
|
+
with PypiClient() as client:
|
|
76
|
+
result = client.publisher.upload(artifacts, repository="testpypi")
|
|
77
|
+
print(result.files)
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
Twine reads `TWINE_USERNAME` and `TWINE_PASSWORD` from the environment, or can
|
|
81
|
+
receive a token explicitly without placing it in process arguments:
|
|
82
|
+
|
|
83
|
+
```python
|
|
84
|
+
import os
|
|
85
|
+
from pathlib import Path
|
|
86
|
+
|
|
87
|
+
from pypi_sdk import PypiClient
|
|
88
|
+
|
|
89
|
+
token = os.environ["PYPI_API_TOKEN"]
|
|
90
|
+
with PypiClient() as client:
|
|
91
|
+
client.publisher.upload(
|
|
92
|
+
Path("dist").glob("*"),
|
|
93
|
+
repository="pypi",
|
|
94
|
+
token=token,
|
|
95
|
+
)
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
The equivalent CLI command is:
|
|
99
|
+
|
|
100
|
+
```console
|
|
101
|
+
pypi-sdk upload --repository testpypi dist\your_package-1.0.0-py3-none-any.whl
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
The publisher delegates metadata handling and the upload protocol to Twine.
|
|
105
|
+
It does not build distributions; use `python -m build` or your project's
|
|
106
|
+
existing build backend first.
|
|
107
|
+
|
|
108
|
+
## Automated publishing with Trusted Publishing
|
|
109
|
+
|
|
110
|
+
For CI, prefer PyPI Trusted Publishing over long-lived API tokens. Configure
|
|
111
|
+
the GitHub repository and workflow as a trusted publisher in the PyPI project
|
|
112
|
+
settings using the GitHub repository owner, repository name, `publish.yml`, and
|
|
113
|
+
the `pypi` environment. Configure the matching GitHub Environment (add
|
|
114
|
+
protection rules if desired), then copy
|
|
115
|
+
[`examples/publish.yml`](examples/publish.yml) to
|
|
116
|
+
`.github/workflows/publish.yml` in the package being released. The workflow
|
|
117
|
+
builds and validates distributions, then publishes them through PyPI's official
|
|
118
|
+
GitHub Action using OIDC.
|
|
119
|
+
See the [Trusted Publishing guide](https://docs.pypi.org/trusted-publishers/).
|
|
120
|
+
|
|
121
|
+
## API policies and boundaries
|
|
122
|
+
|
|
123
|
+
- The SDK identifies itself with a `User-Agent` and honors PyPI's JSON
|
|
124
|
+
representations. The Simple Index HTML representation is not wrapped; the
|
|
125
|
+
docs recommend its JSON form for new integrations.
|
|
126
|
+
- If polling for updates, prefer RSS feeds and avoid bursts of thousands of
|
|
127
|
+
requests. The current client does not yet expose conditional ETag requests.
|
|
128
|
+
- Use the Simple Index for distribution files and verify their advertised
|
|
129
|
+
hashes after downloading.
|
|
130
|
+
- File upload creates releases one file at a time. The first file for a
|
|
131
|
+
version creates that release and fixes its metadata. To correct a release,
|
|
132
|
+
publish a new version.
|
|
133
|
+
- Project administration and Trusted Publisher setup happen in PyPI's web
|
|
134
|
+
interface; this SDK does not claim unsupported account-management endpoints.
|
|
135
|
+
|
|
136
|
+
See the [PyPI API documentation](https://docs.pypi.org/api/) and the
|
|
137
|
+
[Python Packaging User Guide](https://packaging.python.org/).
|
|
138
|
+
|
|
139
|
+
## Development
|
|
140
|
+
|
|
141
|
+
```console
|
|
142
|
+
uv sync --group dev --group docs
|
|
143
|
+
uv run ruff check .
|
|
144
|
+
uv run ruff format --check .
|
|
145
|
+
uv run mypy src
|
|
146
|
+
uv run basedpyright
|
|
147
|
+
uv run pytest
|
|
148
|
+
uv run --group docs mkdocs build --strict
|
|
149
|
+
uv build
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
Tests use mocked HTTP and do not upload packages or contact PyPI. Optional CPU
|
|
153
|
+
benchmarks are available with pytest-benchmark:
|
|
154
|
+
|
|
155
|
+
```console
|
|
156
|
+
uv run --group benchmark pytest benchmarks --no-cov --benchmark-only
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
BenchCore measurements require Python 3.12 or later:
|
|
160
|
+
|
|
161
|
+
```console
|
|
162
|
+
uv run --group benchcore pytest benchmarks/benchcore_cases.py --no-cov --benchcore-save=.benchcore
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
See [Getting started](docs/quickstart.md), [API reference](docs/api.md),
|
|
166
|
+
[publishing guide](docs/publishing.md), [development guide](docs/development.md),
|
|
167
|
+
[contributing](CONTRIBUTING.md), and the [changelog](CHANGELOG.md).
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# Security Policy
|
|
2
|
+
|
|
3
|
+
## Supported versions
|
|
4
|
+
|
|
5
|
+
Security fixes target the latest supported release. Before a stable release,
|
|
6
|
+
the project has no older supported release lines or service-level guarantees.
|
|
7
|
+
|
|
8
|
+
## Reporting a vulnerability
|
|
9
|
+
|
|
10
|
+
Report suspected vulnerabilities privately to
|
|
11
|
+
ramirez.ruiz.eliezer@gmail.com. Include the affected version, impact,
|
|
12
|
+
and a minimal reproduction using synthetic credentials. Do not publish tokens,
|
|
13
|
+
personal data, or exploit details in public issues. No response-time commitment
|
|
14
|
+
is currently offered.
|
|
15
|
+
|
|
16
|
+
## Publishing credentials
|
|
17
|
+
|
|
18
|
+
Prefer PyPI Trusted Publishing in CI. For local publishing, use a project-scoped
|
|
19
|
+
API token and pass it through the SDK's `token` parameter or Twine's
|
|
20
|
+
`TWINE_PASSWORD` environment variable. Never commit tokens, print them, or place
|
|
21
|
+
them in command-line arguments. Revoke exposed tokens in PyPI; deleting a token
|
|
22
|
+
from a later commit does not revoke it.
|
|
23
|
+
|
|
24
|
+
The SDK keeps upload credentials out of read requests and subprocess arguments.
|
|
25
|
+
It cannot protect secrets that an application logs or passes to unrelated
|
|
26
|
+
processes. Uploading is an external side effect; use TestPyPI to validate a
|
|
27
|
+
workflow before production.
|