Skip to content

Commit b51d79b

Browse files
authored
Merge pull request #1112 from YasenT/agents
MD files for AI tools
2 parents 49c619d + ff746a7 commit b51d79b

File tree

2 files changed

+116
-0
lines changed

2 files changed

+116
-0
lines changed

AGENTS.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
CLAUDE.md

CLAUDE.md

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
# CLAUDE.md
2+
3+
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
4+
5+
## What This Project Is
6+
7+
`pulp_python` is a Pulp plugin that enables self-hosted, PyPI-compatible Python package repositories. It is a Django application that integrates with [pulpcore](https://github.com/pulp/pulpcore) via the Pulp plugin API. Key capabilities: sync from PyPI, upload packages, serve via pip, pull-through caching, versioned repos, PEP 740 attestations.
8+
9+
## Development Commands
10+
11+
### Linting
12+
```bash
13+
# Code formatting check
14+
black --check --diff .
15+
16+
# Style/docstring linting
17+
flake8
18+
19+
# Run both via CI scripts
20+
.ci/scripts/extra_linting.sh
21+
.ci/scripts/check_pulpcore_imports.sh
22+
```
23+
24+
**Style rules** (`.flake8`): max line length 100, black-compatible, docstrings required on public methods (with several D-codes ignored — see `.flake8`).
25+
26+
### Testing
27+
28+
Tests require a running Pulp instance. Functional tests use pytest fixtures from `pulp_python/pytest_plugin.py` and connect to a live API.
29+
30+
```bash
31+
# Run all tests
32+
pytest pulp_python/tests/
33+
34+
# Run only unit tests (no Pulp instance needed)
35+
pytest pulp_python/tests/unit/
36+
37+
# Run a single functional test file
38+
pytest pulp_python/tests/functional/api/test_sync.py
39+
40+
# Run a single test by name
41+
pytest pulp_python/tests/functional/api/test_sync.py::test_name
42+
```
43+
44+
### Building
45+
```bash
46+
# Build the Python distribution wheel
47+
python -m build
48+
49+
# Install in development mode
50+
pip install -e .
51+
```
52+
53+
### Changelog Entries
54+
55+
New changelog fragments go in `CHANGES/` using towncrier format. See `pyproject.toml` `[tool.towncrier]` for configuration.
56+
57+
## Architecture
58+
59+
### Plugin Structure
60+
61+
This follows the standard Pulp plugin pattern. The plugin registers itself via the entry point `pulpcore.plugin``pulp_python.app.PulpPythonPluginAppConfig`.
62+
63+
All application code lives in `pulp_python/app/`:
64+
65+
| File/Dir | Purpose |
66+
|---|---|
67+
| `models.py` | Django models for all content types and repository objects |
68+
| `serializers.py` | DRF serializers with validation and metadata extraction |
69+
| `viewsets.py` | DRF viewsets implementing the REST API |
70+
| `urls.py` | URL routing — PyPI API endpoints |
71+
| `utils.py` | Metadata extraction, PyPI template rendering, canonicalization |
72+
| `provenance.py` | PEP 740 attestation/provenance validation logic |
73+
| `tasks/` | Celery async tasks (sync, publish, upload, repair, vulnerability) |
74+
| `pypi/` | PyPI-specific views (Simple API, Legacy upload, Metadata, Provenance) |
75+
| `settings.py` | Django settings additions |
76+
| `migrations/` | Database migrations |
77+
78+
### Core Models
79+
80+
- **`PythonPackageContent`** — the main content type; stores all Python package metadata (PEP 440/core-metadata fields) plus release info (filename, sha256, size). Unique per `(sha256, _pulp_domain)`.
81+
- **`PackageProvenance`** — PEP 740 provenance objects linked to a `PythonPackageContent`.
82+
- **`PythonRepository`** — Repository; supports `autopublish`, `PULL_THROUGH_SUPPORTED = True`. Calls `tasks.publish()` on new versions if `autopublish` is set.
83+
- **`PythonRemote`** — Remote with package filtering (`includes`, `excludes`, `package_types`, `keep_latest_packages`, `exclude_platforms`, `prereleases`, `provenance`).
84+
- **`PythonPublication`** — Publication for generated PyPI Simple API index files.
85+
- **`PythonDistribution`** — Distribution serving content via `content_handler()` which generates JSON API responses and handles Simple API serving from remote storage.
86+
- **`NormalizeName`** — A custom Django `Transform` that normalizes package names per PEP 426 (regex replace `., _, -``-`, lowercased). Used as `name__normalize=value` in queries.
87+
88+
### PyPI API Endpoints (`urls.py`)
89+
90+
```
91+
pypi/<domain>/<path>/legacy/ → UploadView (twine/pip upload)
92+
pypi/<domain>/<path>/integrity/... → ProvenanceView (PEP 740)
93+
pypi/<domain>/<path>/pypi/<meta>/ → MetadataView (JSON API)
94+
pypi/<domain>/<path>/simple/... → SimpleView (pip simple index)
95+
```
96+
97+
### Async Tasks (`tasks/`)
98+
99+
- **`sync.py`** — Syncs packages from a remote (PyPI or compatible). Uses `bandersnatch` and `pypi-simple`.
100+
- **`publish.py`** — Creates a `PythonPublication` with Simple API index files.
101+
- **`upload.py`** — Handles package uploads (`upload` for single, `upload_group` for multi-upload).
102+
- **`repair.py`** — Re-downloads missing artifacts.
103+
- **`vulnerability_report.py`** — Fetches vulnerability data for repository content.
104+
105+
### Test Fixtures (`pytest_plugin.py`)
106+
107+
The pytest plugin defines session-scoped and function-scoped fixtures for all major objects: `python_repo_factory`, `python_remote_factory`, `python_distribution_factory`, `python_publication_factory`, `python_content_factory`, `python_repo_with_sync`. Functional tests depend on a running Pulp instance configured via environment.
108+
109+
### Key Conventions
110+
111+
- The plugin is domain-compatible (`domain_compatible = True`). All content models have a `_pulp_domain` FK.
112+
- Package name lookups always use the `NormalizeName` transform: `name__normalize=canonicalize_name(name)`.
113+
- Content deduplication is enforced in `PythonRepository.finalize_new_version()` via pulpcore's `remove_duplicates()`.
114+
- Access policies use `AutoAddObjPermsMixin` and role-based permissions defined in each model's `Meta.permissions`.
115+
- Changelog entries use towncrier; fragment files belong in `CHANGES/`.

0 commit comments

Comments
 (0)