diff --git a/AGENTS.md b/AGENTS.md index 6d22cf1..bf0e6a4 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,41 +1,63 @@ # AGENTS.md -## Project Overview +Python client for the Crowdin API v2 and Crowdin Enterprise API v2 (PyPI: `crowdin-api-client`, import: `crowdin_api`). -Python client library for Crowdin API v2 and Crowdin Enterprise API v2. +Supports Python 3.8+, so write 3.8-compatible code: no `X | Y` unions, no `match`, and import `TypedDict` from `crowdin_api.typing`. -Main structure: -- Source code: `crowdin_api/` -- Tests: `crowdin_api/tests/` and `crowdin_api/api_resources/**/tests/` +## Layout -## Setup Commands +- `crowdin_api/client.py` — `CrowdinClient`; one hand-written `@property` per resource +- `crowdin_api/api_resources//` — one package per API resource: `resource.py`, `types.py` (request TypedDicts), `enums.py`, `tests/test__resources.py` +- `crowdin_api/api_resources/abstract/resources.py` — `BaseResource` +- `crowdin_api/requester.py` — `APIRequester` (session, retries, error mapping) -- Install dependencies: `python -m pip install --upgrade pip && pip install -r requirements/requirements-dev.txt` -- Run tests: `pytest` -- Run one test file: `pytest crowdin_api/api_resources/.../tests/test_*.py` -- Lint: `flake8 . --count --show-source --statistics` +## Commands -## Code And Testing Expectations +- Install: `pip install -r requirements/requirements-dev.txt` +- Test (all): `pytest` — `setup.cfg` addopts enforce a 95% coverage gate +- Test (one file): `pytest crowdin_api/api_resources//tests/test_*.py --no-cov` — without `--no-cov` the coverage gate fails any partial run even when all tests pass +- Lint (what CI runs): `flake8 . --count --show-source --statistics` +- Format: `pre-commit run --all-files` (black `-l 100`, isort, flake8, xenon) -- Add or update unit tests for behavior changes. -- Keep public API and model changes backward compatible unless explicitly intended. -- Follow existing style and lint configuration (`setup.cfg`, `flake8`). -- Keep changes focused and consistent with existing resource patterns. +`--doctest-modules` is active: pytest imports every module in `crowdin_api/`, and any `>>>` in a docstring runs as a test. -## Notes For API Details +## Adding or changing an endpoint -Always use Crowdin/Crowdin Enterprise `llms.txt` index files for API method details. Choose the correct index by environment first, then project type. +Fetch the endpoint spec first (see Crowdin API reference below). Then: -Use these URLs: +1. Implement the method on the `*Resource` class in `crowdin_api/api_resources//resource.py`: + - List endpoints call `self._get_entire_data(method="get", path=..., params=...)` so `with_fetch_all()` pagination works; everything else calls `self.requester.request(...)`. + - Project-scoped methods take `projectId: Optional[int] = None` and resolve it via `projectId or self.get_project_id()`. + - Request body shapes go in `types.py` as TypedDicts; enum values in `enums.py`. Enums and `Sorting` objects can be passed straight into `params`/`request_data` — the custom JSON encoder serializes them, and `None` values are stripped before sending. + - End the docstring with `Link to documentation:` and the developer.crowdin.com operation URL (pdoc publishes these). +2. For a new resource, register it in three places: an import plus `__all__` entry in `crowdin_api/api_resources/__init__.py` (alphabetical), a `@property` on `CrowdinClient` in `client.py` (copy an existing property; use the enterprise-guard or per-platform variant when the API is Enterprise-only or differs by platform), and one tuple in each of the two parametrize lists in `crowdin_api/tests/test_client.py`. Some resource classes exist but were never registered (e.g. `BranchesResource`, `StringCorrectionsResource`) — "adding" one of those is exactly this registration work. +3. Test in the resource's `tests/` dir: patch the requester with `@mock.patch("crowdin_api.requester.APIRequester.request")`, call the method, then `m_request.assert_called_once_with(method=..., path=..., ...)` with the exact kwargs. The `base_absolut_url` fixture (spelled without the second "e") provides the base URL. No test performs real HTTP. -- https://support.crowdin.com/_llms-txt/api/crowdin/file-based.txt - Crowdin API (file-based projects, preferred first) -- https://support.crowdin.com/_llms-txt/api/crowdin/string-based.txt - Crowdin API (string-based projects) -- https://support.crowdin.com/_llms-txt/api/enterprise/file-based.txt - Crowdin Enterprise API (file-based projects) -- https://support.crowdin.com/_llms-txt/api/enterprise/string-based.txt - Crowdin Enterprise API (string-based projects) +A complete new resource touches ~8 files: the four package files (`__init__.py` is one line: `__pdoc__ = {'tests': False}`), the resource's test file, and the three registration files. -Each index contains links to method details (for example, `.../api.projects.strings.get.txt`). +## Crowdin API reference -## Pull Requests And Commits +Before implementing or changing any endpoint, fetch its spec from the llms.txt indexes (pick by environment, then project type): -- Use Conventional Commits for commit messages and PR titles. -- Before opening a PR, run lint and tests locally. +- https://support.crowdin.com/_llms-txt/api/crowdin/file-based.txt — Crowdin API, file-based projects (start here) +- https://support.crowdin.com/_llms-txt/api/crowdin/string-based.txt — Crowdin API, string-based projects +- https://support.crowdin.com/_llms-txt/api/enterprise/file-based.txt — Crowdin Enterprise API, file-based projects +- https://support.crowdin.com/_llms-txt/api/enterprise/string-based.txt — Crowdin Enterprise API, string-based projects + +Each index links one spec file per route (e.g. `.../api.projects.strings.get.txt`) with the exact request and response shapes. + +## Conventions + +- Conventional Commits for commit messages and PR titles; CI lints PR titles. +- PRs target `main`. +- Keep the public API backward compatible; mark removals with `@deprecated(...)` (from the `deprecated` package) instead of deleting. +- Never edit `__version__` in `crowdin_api/__init__.py` — the Release workflow bumps it. + +## PR checklist + +A change is ready when: + +1. `pytest` passes, including the 95% coverage gate, +2. `flake8 . --count --show-source --statistics` is clean, +3. every new or changed endpoint method has a test asserting the exact requester call, and +4. every new or changed public method's docstring ends with its documentation link. diff --git a/CLAUDE.md b/CLAUDE.md new file mode 120000 index 0000000..47dc3e3 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1 @@ +AGENTS.md \ No newline at end of file