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
119 changes: 119 additions & 0 deletions .github/workflows/pysof-ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
# name: pysof CI

# on:
# push:
# branches: [main, epic/pysof]
# paths:
# - 'crates/pysof/**'
# - '.github/workflows/pysof-ci.yml'
# pull_request:
# branches: [main, epic/pysof]
# paths:
# - 'crates/pysof/**'
# - '.github/workflows/pysof-ci.yml'

# defaults:
# run:
# working-directory: crates/pysof

# jobs:
# lint-and-test:
# name: pysof Lint and Test (Python 3.11)
# runs-on: [self-hosted, Linux]

# steps:
# - name: Checkout code
# uses: actions/checkout@v4

# - name: Install uv
# uses: astral-sh/setup-uv@v3
# with:
# version: "latest"

# - name: Set up Python 3.11
# run: uv python install 3.11

# - name: Create virtual environment
# run: uv venv --python 3.11

# - name: Install dependencies
# run: uv sync --group dev

# - name: Format check
# run: uv run ruff format --check src tests

# - name: Lint check
# run: uv run lint

# - name: Type check
# run: uv run typecheck

# - name: Run tests
# run: uv run test-cov

# - name: Upload coverage to Codecov
# uses: codecov/codecov-action@v4
# with:
# file: ./crates/pysof/coverage.xml
# flags: pysof
# name: pysof-coverage
# fail_ci_if_error: false
# env:
# CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}

# # Test on multiple platforms to ensure compatibility
# test-platforms:
# name: pysof Test on ${{ matrix.os }}
# runs-on: ${{ matrix.runner }}
# strategy:
# matrix:
# include:
# - os: Linux
# runner: [self-hosted, Linux]
# - os: Windows
# runner: [self-hosted, Windows]

# steps:
# - name: Checkout code
# uses: actions/checkout@v4

# - name: Install uv
# uses: astral-sh/setup-uv@v3
# with:
# version: "latest"

# - name: Set up Python 3.11
# run: uv python install 3.11

# - name: Create virtual environment (Linux)
# if: runner.os != 'Windows'
# run: uv venv --python 3.11
# working-directory: crates/pysof

# - name: Create virtual environment (Windows)
# if: runner.os == 'Windows'
# shell: cmd
# run: uv venv --python 3.11
# working-directory: crates/pysof

# - name: Install dependencies (Linux)
# if: runner.os != 'Windows'
# run: uv sync --group dev
# working-directory: crates/pysof

# - name: Install dependencies (Windows)
# if: runner.os == 'Windows'
# shell: cmd
# run: uv sync --group dev
# working-directory: crates/pysof

# - name: Run tests (Linux)
# if: runner.os != 'Windows'
# run: uv run test
# working-directory: crates/pysof

# - name: Run tests (Windows)
# if: runner.os == 'Windows'
# shell: cmd
# run: uv run test
# working-directory: crates/pysof
78 changes: 78 additions & 0 deletions crates/pysof/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
# Python virtual environments
.venv/
venv/
env/

# Python bytecode
__pycache__/
*.py[cod]
*$py.class

# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST

# PyInstaller
*.manifest
*.spec

# Installer logs
pip-log.txt
pip-delete-this-directory.txt

# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
*.py,cover
.hypothesis/
.pytest_cache/
.coverage.xml

# Jupyter Notebook
.ipynb_checkpoints

# pyenv
.python-version

# uv
.uv/

# mypy
.mypy_cache/
.dmypy.json
dmypy.json

# Pyre type checker
.pyre/

# IDE
.vscode/
.idea/
*.swp
*.swo

# OS
.DS_Store
Thumbs.db
20 changes: 14 additions & 6 deletions crates/pysof/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,11 +43,13 @@ crates/pysof/
- [x] Package skeleton with src layout
- [x] `pyproject.toml` targeting Python 3.11
- [x] README with quickstart, layout, roadmap
- [ ] Define Python public API surface in `pysof/__init__.py`
- [ ] Add `ruff` (lint) and `mypy` (types) configs
- [ ] Add `uv` scripts for fmt, lint, test
- [ ] Add minimal tests: import/package metadata/version
- [ ] Add CI workflow for Python 3.11: lint + tests
- [x] Define Python public API surface in `pysof/__init__.py`
- [x] Add `ruff` (lint) and `mypy` (types) configs
- [x] Add `uv` scripts for fmt, lint, test
- [x] Add minimal tests: import/package metadata/version
- [x] Add CI workflow for Python 3.11: lint + tests (Linux/Windows self-hosted)
- [ ] Install uv on self-hosted runners to enable CI execution
- [ ] Add macOS self-hosted runner support to CI

- v1 (Rust bindings and wheels)

Expand All @@ -74,7 +76,8 @@ crates/pysof/
- [ ] `validate_bundle(bundle: dict) -> bool` - Pre-validate Bundle structure
- [ ] `parse_content_type(mime_type: str) -> str` - Parse MIME types to format strings
- [ ] `get_supported_fhir_versions() -> List[str]` - List available FHIR versions
- [ ] Add wheel builds for Windows, macOS (x86_64, arm64), Linux (manylinux/musllinux)
- [ ] Add wheel builds for Windows, Linux (manylinux/musllinux)
- [ ] Add macOS wheel builds (x86_64, arm64) when self-hosted macOS runner available
- [ ] Add integration tests mirroring Rust crate examples
- [ ] Provide examples: in-memory, file-based, stdin/stdout-like workflows

Expand All @@ -95,6 +98,11 @@ crates/pysof/
- [ ] FHIRPath expression syntax validation
- [ ] ViewDefinition linting and optimization suggestions

- Infrastructure/DevOps
- [ ] Install uv package manager on self-hosted CI runners
- [ ] Set up macOS self-hosted runner (when needed for wheel distribution)
- [ ] Configure Python 3.11+ on all CI environments

- Future (Server integration and ecosystem)
- [ ] **HTTP Client Integration:**
- [ ] Optional async client wrappers for `sof-server` HTTP endpoints
Expand Down
118 changes: 118 additions & 0 deletions crates/pysof/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,125 @@ classifiers = [
]
dependencies = []

[dependency-groups]
dev = [
"ruff>=0.1.0",
"mypy>=1.5.0",
"pytest>=7.4.0",
"pytest-cov>=4.1.0",
]

[tool.uv]
dev-dependencies = [
"ruff>=0.1.0",
"mypy>=1.5.0",
"pytest>=7.4.0",
"pytest-cov>=4.1.0",
]

[project.scripts]
# No CLI scripts yet

[tool.uv.scripts]
fmt = "ruff format src tests"
lint = "ruff check src tests"
lint-fix = "ruff check --fix src tests"
typecheck = "mypy src"
test = "pytest tests/ -v"
test-cov = "pytest tests/ -v --cov=pysof --cov-report=term-missing --cov-report=xml"
check-all = ["lint", "typecheck", "test"]

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

[tool.ruff]
target-version = "py311"
line-length = 88
select = [
"E", # pycodestyle errors
"W", # pycodestyle warnings
"F", # pyflakes
"I", # isort
"B", # flake8-bugbear
"C4", # flake8-comprehensions
"UP", # pyupgrade
]
ignore = [
"E501", # line too long, handled by black
]
src = ["src"]
exclude = [
".bzr",
".direnv",
".eggs",
".git",
".hg",
".mypy_cache",
".nox",
".pants.d",
".ruff_cache",
".svn",
".tox",
".venv",
"__pypackages__",
"_build",
"buck-out",
"build",
"dist",
"node_modules",
"venv",
]

[tool.ruff.per-file-ignores]
"__init__.py" = ["F401"] # Allow unused imports in __init__.py

[tool.mypy]
python_version = "3.11"
warn_return_any = true
warn_unused_configs = true
disallow_untyped_defs = true
disallow_incomplete_defs = true
check_untyped_defs = true
disallow_untyped_decorators = true
no_implicit_optional = true
warn_redundant_casts = true
warn_unused_ignores = true
warn_no_return = true
warn_unreachable = true
strict_equality = true
show_error_codes = true

[[tool.mypy.overrides]]
module = "tests.*"
disallow_untyped_defs = false

[tool.pytest.ini_options]
testpaths = ["tests"]
python_files = ["test_*.py"]
python_classes = ["Test*"]
python_functions = ["test_*"]
addopts = [
"--strict-config",
"--strict-markers",
"--disable-warnings",
]

[tool.coverage.run]
source = ["src"]
branch = true

[tool.coverage.report]
exclude_lines = [
"pragma: no cover",
"def __repr__",
"if self.debug:",
"if settings.DEBUG",
"raise AssertionError",
"raise NotImplementedError",
"if 0:",
"if __name__ == .__main__.:",
"class .*\\bProtocol\\):",
"@(abc\\.)?abstractmethod",
]


Loading