diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml new file mode 100644 index 0000000..5540ca5 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -0,0 +1,52 @@ +name: Bug report +description: Something behaves incorrectly +labels: ["bug"] +body: + - type: dropdown + id: package + attributes: + label: Package + description: Which distribution is affected? + options: + - dexpace-sdk-core + - dexpace-sdk-http-stdlib + - dexpace-sdk-http-httpx + - dexpace-sdk-http-aiohttp + - dexpace-sdk-http-requests + - not sure + validations: + required: true + - type: textarea + id: description + attributes: + label: Description + description: What happened, and what did you expect instead? + validations: + required: true + - type: textarea + id: reproduction + attributes: + label: Minimal reproduction + description: The smallest code snippet that triggers the bug. + render: python + validations: + required: true + - type: textarea + id: traceback + attributes: + label: Traceback / output + render: text + - type: input + id: python-version + attributes: + label: Python version + placeholder: "3.12.4" + validations: + required: true + - type: input + id: sdk-version + attributes: + label: SDK version(s) + placeholder: "dexpace-sdk-core 0.1.0" + validations: + required: true diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 0000000..88c41f8 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,5 @@ +blank_issues_enabled: true +contact_links: + - name: Security vulnerability + url: https://github.com/dexpace/python-sdk/security/advisories/new + about: Please report security issues privately, not as public issues. diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml new file mode 100644 index 0000000..40368c6 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.yml @@ -0,0 +1,25 @@ +name: Feature request +description: Propose a new capability or improvement +labels: ["enhancement"] +body: + - type: textarea + id: problem + attributes: + label: Problem + description: What are you trying to do that the SDK doesn't support today? + validations: + required: true + - type: textarea + id: proposal + attributes: + label: Proposed solution + description: >- + What would the API look like? Note that core stays free of new + runtime dependencies — third-party needs belong behind the + `HttpClient`/`Serde` seams or in a transport package. + validations: + required: true + - type: textarea + id: alternatives + attributes: + label: Alternatives considered diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000..b81bed2 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,12 @@ +## What + + + +## Checklist + +- [ ] `uv run pytest -q` passes +- [ ] `uv run mypy --strict` passes +- [ ] `uv run ruff check` and `uv run ruff format --check` pass +- [ ] New/changed public symbols have Google-style docstrings and appear in `__all__` +- [ ] New `.py` files carry the two-line MIT licence header +- [ ] Commit messages use the `feat:` / `fix:` / `chore:` / `docs:` / `ci:` prefixes diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..3c7da9d --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,17 @@ +version: 2 +updates: + - package-ecosystem: github-actions + directory: / + schedule: + interval: weekly + groups: + actions: + patterns: ["*"] + + - package-ecosystem: uv + directory: / + schedule: + interval: weekly + groups: + python-deps: + patterns: ["*"] diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ade2364..75d461b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -10,6 +10,9 @@ concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true +permissions: + contents: read + jobs: test: name: test (Python ${{ matrix.python-version }}) @@ -20,17 +23,13 @@ jobs: python-version: ["3.12", "3.13", "3.14"] steps: - name: Checkout - uses: actions/checkout@v4 - - - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v5 - with: - python-version: ${{ matrix.python-version }} + uses: actions/checkout@v6 - name: Install uv - uses: astral-sh/setup-uv@v3 + uses: astral-sh/setup-uv@v8.2.0 with: enable-cache: true + python-version: ${{ matrix.python-version }} - name: Sync workspace run: uv sync diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 0000000..730e6cc --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,40 @@ +# Code of Conduct + +## Our pledge + +We as members, contributors, and maintainers pledge to make participation in +this project a harassment-free experience for everyone, regardless of age, +body size, visible or invisible disability, ethnicity, sex characteristics, +gender identity and expression, level of experience, education, socio-economic +status, nationality, personal appearance, race, religion, or sexual identity +and orientation. + +## Our standards + +Examples of behaviour that contributes to a positive environment: + +- Showing empathy and kindness toward other people +- Being respectful of differing opinions, viewpoints, and experiences +- Giving and gracefully accepting constructive feedback +- Focusing on what is best for the community + +Examples of unacceptable behaviour: + +- Trolling, insulting or derogatory comments, and personal or political attacks +- Public or private harassment +- Publishing others' private information without explicit permission +- Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behaviour may be +reported to the maintainers at +[o.mazari.om63@gmail.com](mailto:o.mazari.om63@gmail.com). All complaints will +be reviewed and investigated promptly and fairly. Maintainers are obligated to +respect the privacy and security of the reporter of any incident. + +## Attribution + +This Code of Conduct is adapted from the +[Contributor Covenant](https://www.contributor-covenant.org), version 2.1. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..83b90db --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,65 @@ +# Contributing + +Thanks for your interest in the Dexpace Python SDK. External pull requests +are welcome — this page covers everything you need to get a change merged. + +## Setup + +The repository is a [`uv`](https://docs.astral.sh/uv/)-managed workspace of +five packages. One sync provisions everything in editable mode along with +the dev toolchain: + +```bash +git clone https://github.com/dexpace/python-sdk.git +cd python-sdk +uv sync +``` + +## Quality gates + +Every pull request must pass the same four gates CI runs (on Python 3.12, +3.13, and 3.14): + +```bash +uv run pytest -q # full test suite +uv run mypy --strict # type-check +uv run ruff check # lint +uv run ruff format --check # formatting +``` + +Run them locally before opening a PR. + +## Conventions + +The full convention set lives in [`CLAUDE.md`](CLAUDE.md). The essentials: + +- **Python 3.12+** with modern syntax: `X | None`, built-in generics, + PEP 695 type parameters, `from __future__ import annotations` everywhere. +- **Immutable models**: `@dataclass(frozen=True, slots=True)`; mutate via + `dataclasses.replace` or `with_*` helpers — no builders. +- **`Protocol` for SPIs, `ABC` for shared behaviour.** +- **No new runtime dependencies.** `core` ships against the standard + library plus `furl` only; new third-party needs belong behind the + `HttpClient` or `Serde` seams, or in a new transport package. +- **Google-style docstrings** on every public symbol; functions capped at + 50 lines. +- **MIT licence header** (two lines) at the top of every `.py` file, src + and tests alike. + +## Commit messages + +Use the prefixes the history already follows: + +| Prefix | Use for | +|----------|----------------------------------| +| `feat:` | new features | +| `fix:` | bug fixes | +| `chore:` | refactors and cleanup | +| `docs:` | documentation-only changes | +| `ci:` | CI configuration | + +## Reporting issues + +Use the [issue templates](https://github.com/dexpace/python-sdk/issues/new/choose). +For security vulnerabilities, follow [`SECURITY.md`](SECURITY.md) instead of +opening a public issue. diff --git a/README.md b/README.md index 7a88468..761de24 100644 --- a/README.md +++ b/README.md @@ -244,8 +244,14 @@ Documented in [`CLAUDE.md`](CLAUDE.md). The short version: ## Contributing -External pull requests are welcome. Run the gates above before opening -one, and follow the conventions in [`CLAUDE.md`](CLAUDE.md). +External pull requests are welcome. See [`CONTRIBUTING.md`](CONTRIBUTING.md) +for setup, the quality gates, and commit conventions, and +[`CODE_OF_CONDUCT.md`](CODE_OF_CONDUCT.md) for community expectations. + +## Security + +To report a vulnerability, follow [`SECURITY.md`](SECURITY.md) — please do +not open a public issue. ## License diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 0000000..e54af81 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,36 @@ +# Security Policy + +## Supported versions + +| Version | Supported | +|---------|--------------------| +| 0.1.x | :white_check_mark: | + +## Reporting a vulnerability + +Please **do not** open a public issue for security vulnerabilities. + +Instead, report privately via +[GitHub private vulnerability reporting](https://github.com/dexpace/python-sdk/security/advisories/new) +(Security tab → "Report a vulnerability"). If you cannot use GitHub, email +[o.mazari.om63@gmail.com](mailto:o.mazari.om63@gmail.com) with +`[SECURITY]` in the subject line. + +Include what you can of the following: + +- The affected package(s) and version(s) +- A description of the vulnerability and its impact +- Steps or a proof of concept to reproduce it + +You can expect an acknowledgement within a few days. Please allow time for +a fix to land and be released before disclosing publicly. + +## Scope notes + +- The SDK is a **toolkit**, not a service: it executes no network I/O of + its own. Transport-level vulnerabilities (TLS, connection handling) + usually belong to the underlying HTTP library (`httpx`, `aiohttp`, + `requests`, or the standard library) — report those upstream. +- In scope here: credential handling (`http.auth`), header/URL redaction + in logging, redirect safety (`Authorization` stripping, userinfo + dropping), body capture, and challenge parsing. diff --git a/packages/dexpace-sdk-core/pyproject.toml b/packages/dexpace-sdk-core/pyproject.toml index ff65643..81c6dba 100644 --- a/packages/dexpace-sdk-core/pyproject.toml +++ b/packages/dexpace-sdk-core/pyproject.toml @@ -1,32 +1,36 @@ [build-system] -requires = ["hatchling"] +requires = ["hatchling>=1.27"] build-backend = "hatchling.build" [project] name = "dexpace-sdk-core" version = "0.1.0" -description = "Zero-dependency Python SDK core for building HTTP client libraries." +description = "Toolkit core for building Python HTTP client libraries: immutable models, staged policy pipelines, auth, and observability." readme = "README.md" requires-python = ">=3.12" -license = { file = "LICENSE.md" } +license = "MIT" +license-files = ["LICENSE.md"] authors = [{ name = "Omar Aljarrah", email = "o.mazari.om63@gmail.com" }] -keywords = ["sdk", "http", "client", "toolkit"] +keywords = ["sdk", "http", "client", "toolkit", "pipeline", "openapi"] classifiers = [ "Development Status :: 3 - Alpha", "Intended Audience :: Developers", - "License :: OSI Approved :: MIT License", "Operating System :: OS Independent", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Programming Language :: Python :: 3.14", + "Topic :: Internet :: WWW/HTTP", "Topic :: Software Development :: Libraries", + "Typing :: Typed", ] dependencies = ["furl>=2.1.3"] [project.urls] Homepage = "https://github.com/dexpace/python-sdk" +Documentation = "https://github.com/dexpace/python-sdk/tree/main/docs" Repository = "https://github.com/dexpace/python-sdk" +Issues = "https://github.com/dexpace/python-sdk/issues" [tool.hatch.build.targets.wheel] packages = ["src/dexpace/sdk/core"] diff --git a/packages/dexpace-sdk-http-aiohttp/pyproject.toml b/packages/dexpace-sdk-http-aiohttp/pyproject.toml index 98bb3ff..72cbf1c 100644 --- a/packages/dexpace-sdk-http-aiohttp/pyproject.toml +++ b/packages/dexpace-sdk-http-aiohttp/pyproject.toml @@ -1,5 +1,5 @@ [build-system] -requires = ["hatchling"] +requires = ["hatchling>=1.27"] build-backend = "hatchling.build" [project] @@ -8,20 +8,22 @@ version = "0.1.0" description = "aiohttp-backed async HTTP transport for dexpace-sdk-core." readme = "README.md" requires-python = ">=3.12" -license = { file = "LICENSE.md" } +license = "MIT" +license-files = ["LICENSE.md"] authors = [{ name = "Omar Aljarrah", email = "o.mazari.om63@gmail.com" }] keywords = ["sdk", "http", "aiohttp", "async"] classifiers = [ "Development Status :: 3 - Alpha", "Framework :: AsyncIO", "Intended Audience :: Developers", - "License :: OSI Approved :: MIT License", "Operating System :: OS Independent", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Programming Language :: Python :: 3.14", + "Topic :: Internet :: WWW/HTTP", "Topic :: Software Development :: Libraries", + "Typing :: Typed", ] dependencies = [ "dexpace-sdk-core>=0.1,<0.2", @@ -30,7 +32,9 @@ dependencies = [ [project.urls] Homepage = "https://github.com/dexpace/python-sdk" +Documentation = "https://github.com/dexpace/python-sdk/tree/main/docs" Repository = "https://github.com/dexpace/python-sdk" +Issues = "https://github.com/dexpace/python-sdk/issues" [tool.hatch.build.targets.wheel] packages = ["src/dexpace/sdk/http/aiohttp"] diff --git a/packages/dexpace-sdk-http-httpx/pyproject.toml b/packages/dexpace-sdk-http-httpx/pyproject.toml index 0fa5c91..422a53d 100644 --- a/packages/dexpace-sdk-http-httpx/pyproject.toml +++ b/packages/dexpace-sdk-http-httpx/pyproject.toml @@ -1,5 +1,5 @@ [build-system] -requires = ["hatchling"] +requires = ["hatchling>=1.27"] build-backend = "hatchling.build" [project] @@ -8,19 +8,21 @@ version = "0.1.0" description = "httpx-backed HTTP transports for dexpace-sdk-core." readme = "README.md" requires-python = ">=3.12" -license = { file = "LICENSE.md" } +license = "MIT" +license-files = ["LICENSE.md"] authors = [{ name = "Omar Aljarrah", email = "o.mazari.om63@gmail.com" }] keywords = ["sdk", "http", "httpx"] classifiers = [ "Development Status :: 3 - Alpha", "Intended Audience :: Developers", - "License :: OSI Approved :: MIT License", "Operating System :: OS Independent", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Programming Language :: Python :: 3.14", + "Topic :: Internet :: WWW/HTTP", "Topic :: Software Development :: Libraries", + "Typing :: Typed", ] dependencies = [ "dexpace-sdk-core>=0.1,<0.2", @@ -29,7 +31,9 @@ dependencies = [ [project.urls] Homepage = "https://github.com/dexpace/python-sdk" +Documentation = "https://github.com/dexpace/python-sdk/tree/main/docs" Repository = "https://github.com/dexpace/python-sdk" +Issues = "https://github.com/dexpace/python-sdk/issues" [tool.hatch.build.targets.wheel] packages = ["src/dexpace/sdk/http/httpx"] diff --git a/packages/dexpace-sdk-http-requests/pyproject.toml b/packages/dexpace-sdk-http-requests/pyproject.toml index 67c0b7e..47c69e1 100644 --- a/packages/dexpace-sdk-http-requests/pyproject.toml +++ b/packages/dexpace-sdk-http-requests/pyproject.toml @@ -1,5 +1,5 @@ [build-system] -requires = ["hatchling"] +requires = ["hatchling>=1.27"] build-backend = "hatchling.build" [project] @@ -8,19 +8,21 @@ version = "0.1.0" description = "requests-backed synchronous HTTP transport for dexpace-sdk-core." readme = "README.md" requires-python = ">=3.12" -license = { file = "LICENSE.md" } +license = "MIT" +license-files = ["LICENSE.md"] authors = [{ name = "Omar Aljarrah", email = "o.mazari.om63@gmail.com" }] keywords = ["sdk", "http", "requests"] classifiers = [ "Development Status :: 3 - Alpha", "Intended Audience :: Developers", - "License :: OSI Approved :: MIT License", "Operating System :: OS Independent", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Programming Language :: Python :: 3.14", + "Topic :: Internet :: WWW/HTTP", "Topic :: Software Development :: Libraries", + "Typing :: Typed", ] dependencies = [ "dexpace-sdk-core>=0.1,<0.2", @@ -29,7 +31,9 @@ dependencies = [ [project.urls] Homepage = "https://github.com/dexpace/python-sdk" +Documentation = "https://github.com/dexpace/python-sdk/tree/main/docs" Repository = "https://github.com/dexpace/python-sdk" +Issues = "https://github.com/dexpace/python-sdk/issues" [tool.hatch.build.targets.wheel] packages = ["src/dexpace/sdk/http/requests"] diff --git a/packages/dexpace-sdk-http-stdlib/pyproject.toml b/packages/dexpace-sdk-http-stdlib/pyproject.toml index 25f1c56..7c1a760 100644 --- a/packages/dexpace-sdk-http-stdlib/pyproject.toml +++ b/packages/dexpace-sdk-http-stdlib/pyproject.toml @@ -1,5 +1,5 @@ [build-system] -requires = ["hatchling"] +requires = ["hatchling>=1.27"] build-backend = "hatchling.build" [project] @@ -8,19 +8,21 @@ version = "0.1.0" description = "Reference stdlib HTTP transports (urllib + asyncio) for dexpace-sdk-core." readme = "README.md" requires-python = ">=3.12" -license = { file = "LICENSE.md" } +license = "MIT" +license-files = ["LICENSE.md"] authors = [{ name = "Omar Aljarrah", email = "o.mazari.om63@gmail.com" }] keywords = ["sdk", "http", "client", "urllib", "asyncio"] classifiers = [ "Development Status :: 3 - Alpha", "Intended Audience :: Developers", - "License :: OSI Approved :: MIT License", "Operating System :: OS Independent", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Programming Language :: Python :: 3.14", + "Topic :: Internet :: WWW/HTTP", "Topic :: Software Development :: Libraries", + "Typing :: Typed", ] dependencies = [ "dexpace-sdk-core>=0.1,<0.2", @@ -28,7 +30,9 @@ dependencies = [ [project.urls] Homepage = "https://github.com/dexpace/python-sdk" +Documentation = "https://github.com/dexpace/python-sdk/tree/main/docs" Repository = "https://github.com/dexpace/python-sdk" +Issues = "https://github.com/dexpace/python-sdk/issues" [tool.hatch.build.targets.wheel] packages = ["src/dexpace/sdk/http/stdlib"]