Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
.pytest_cache/
.venv/
__pycache__/
dist/
1 change: 1 addition & 0 deletions .python-version
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
3.13
25 changes: 25 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
## convert-python-sdk

This repository currently contains the Story 1.1 scaffold for Convert's Python SDK.

Canonical package decisions frozen in this story:

- Distribution name: `convert-python-sdk`
- Import package: `convert_sdk`
- Stable public imports: `Core`, `Context`, and `__version__`

The scaffold is intentionally minimal. Feature initialization, configuration loading, local evaluation, and tracking behavior will land in later stories.

### Local Development

```bash
UV_CACHE_DIR=/tmp/uv-cache uv sync --group dev
UV_CACHE_DIR=/tmp/uv-cache uv run pytest
UV_CACHE_DIR=/tmp/uv-cache uv build
Comment on lines +16 to +18

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Hardcoding UV_CACHE_DIR=/tmp/uv-cache is not portable across different operating systems (e.g., Windows) and may fail if the directory is not writable. uv automatically manages its cache in a platform-appropriate location, so this override is generally unnecessary for local development instructions.

Suggested change
UV_CACHE_DIR=/tmp/uv-cache uv sync --group dev
UV_CACHE_DIR=/tmp/uv-cache uv run pytest
UV_CACHE_DIR=/tmp/uv-cache uv build
uv sync --group dev
uv run pytest
uv build

```

### Public Import Boundary

```python
from convert_sdk import Context, Core, __version__
```
36 changes: 36 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
[project]
name = "convert-python-sdk"
version = "0.1.0"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The package version is currently hardcoded in both pyproject.toml and src/convert_sdk/version.py. To avoid duplication and potential inconsistencies, it is recommended to use Hatch's dynamic versioning, treating the source code as the single source of truth.

Suggested change
version = "0.1.0"
dynamic = ["version"]

description = "Framework-agnostic Python SDK scaffold for Convert."
readme = "README.md"
authors = [
{ name = "Usman Abbas", email = "usman.abbas7@gmail.com" }
]
requires-python = ">=3.9"
dependencies = []

[dependency-groups]
dev = [
"pytest>=8.4,<9",
]

[build-system]
requires = ["hatchling>=1.29,<2"]
build-backend = "hatchling.build"

[tool.hatch.build.targets.wheel]
packages = ["src/convert_sdk"]

[tool.hatch.build.targets.wheel.force-include]
"src/convert_sdk/py.typed" = "convert_sdk/py.typed"
Comment on lines +24 to +25

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

This force-include configuration is redundant. Since src/convert_sdk is already defined in the packages list for the wheel target, all non-ignored files within that directory (including py.typed) are included by default by Hatchling. Removing this simplifies the configuration.


[tool.hatch.build.targets.sdist]
include = [
"README.md",
"src/convert_sdk/**/*.py",
"src/convert_sdk/py.typed",
"tests/**/*.py",
]

[tool.pytest.ini_options]
testpaths = ["tests"]
Comment on lines +35 to +36

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

When using dynamic versioning, you need to specify the source of the version metadata for Hatch. This ensures that the version defined in src/convert_sdk/version.py is used as the package version.

Suggested change
[tool.pytest.ini_options]
testpaths = ["tests"]
[tool.pytest.ini_options]
testpaths = ["tests"]
[tool.hatch.version]
path = "src/convert_sdk/version.py"

7 changes: 7 additions & 0 deletions src/convert_sdk/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
"""Stable public import boundary for the Convert Python SDK."""

from .context import Context
from .core import Core
from .version import __version__

__all__ = ["Context", "Core", "__version__"]
8 changes: 8 additions & 0 deletions src/convert_sdk/context.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
"""Per-visitor context placeholder reserved for later stories."""


class Context:
"""Stable root export for visitor-scoped SDK behavior."""

def __repr__(self) -> str:
return "Context()"
8 changes: 8 additions & 0 deletions src/convert_sdk/core.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
"""Public SDK entry point placeholder for future initialization work."""


class Core:
"""Stable root export reserved for SDK initialization and context creation."""

def __repr__(self) -> str:
return "Core()"
1 change: 1 addition & 0 deletions src/convert_sdk/py.typed
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@

3 changes: 3 additions & 0 deletions src/convert_sdk/version.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
"""Version metadata for the public SDK package."""

__version__ = "0.1.0"
20 changes: 20 additions & 0 deletions tests/test_packaging.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
from importlib.metadata import distribution
from pathlib import Path


PROJECT_ROOT = Path(__file__).resolve().parents[1]


def test_distribution_metadata_matches_story_contract() -> None:
dist = distribution("convert-python-sdk")

assert dist.metadata["Name"] == "convert-python-sdk"
assert dist.metadata["Requires-Python"] == ">=3.9"
assert dist.requires in (None, [])


def test_pyproject_freezes_convert_sdk_package_boundary() -> None:
pyproject = (PROJECT_ROOT / "pyproject.toml").read_text(encoding="utf-8")

assert 'packages = ["src/convert_sdk"]' in pyproject
assert '"src/convert_sdk/py.typed" = "convert_sdk/py.typed"' in pyproject
14 changes: 14 additions & 0 deletions tests/test_public_api.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
from importlib import resources

from convert_sdk import Context, Core, __version__


def test_public_import_boundary_is_stable() -> None:
assert Core.__module__ == "convert_sdk.core"
assert Context.__module__ == "convert_sdk.context"
assert __version__ == "0.1.0"
Comment on lines +1 to +9

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Avoid hardcoding the version string in tests. It is more robust to compare the exported __version__ against the package metadata to ensure they are in sync.

Suggested change
from importlib import resources
from convert_sdk import Context, Core, __version__
def test_public_import_boundary_is_stable() -> None:
assert Core.__module__ == "convert_sdk.core"
assert Context.__module__ == "convert_sdk.context"
assert __version__ == "0.1.0"
from importlib import metadata, resources
from convert_sdk import Context, Core, __version__
def test_public_import_boundary_is_stable() -> None:
assert Core.__module__ == "convert_sdk.core"
assert Context.__module__ == "convert_sdk.context"
assert __version__ == metadata.version("convert-python-sdk")



def test_py_typed_marker_is_available() -> None:
marker = resources.files("convert_sdk").joinpath("py.typed")
assert marker.is_file()
176 changes: 176 additions & 0 deletions uv.lock

Large diffs are not rendered by default.