From 6afe20d788a7ca0e992fcb64c6511746762088e6 Mon Sep 17 00:00:00 2001 From: Damian Reeves <957246+DamianReeves@users.noreply.github.com> Date: Mon, 19 Jan 2026 15:13:55 -0600 Subject: [PATCH 1/6] feat: Initial Python project setup with monorepo structure Set up the morphir-python project as a production-ready Python port of Morphir with a monorepo structure supporting separate library and tools packages. Project infrastructure: - mise for tool management (Python 3.14, uv) - uv workspace with two packages: morphir (core library) and morphir-tools (CLI) - Strict type checking with mypy and pyright - Linting and formatting with ruff (Google-style docstrings) - Testing with pytest (unit) and behave (BDD) - GitHub Actions CI/CD workflows - Pre-commit hooks configuration Documentation: - Updated README.md with installation and development instructions - Created AGENTS.md with guidelines for code agents - Created .agents/skills/README.md for agentic skills (Agent Skills spec) This establishes the foundation for implementing the Morphir IR models and tooling in Python, following functional programming principles. --- .agents/skills/README.md | 85 +++++ .config/mise/config.toml | 9 + .config/mise/tasks/build | 11 + .config/mise/tasks/check | 6 + .config/mise/tasks/clean | 17 + .config/mise/tasks/coverage | 5 + .config/mise/tasks/format | 5 + .config/mise/tasks/format-check | 5 + .config/mise/tasks/lint | 5 + .config/mise/tasks/test | 5 + .config/mise/tasks/test-all | 6 + .config/mise/tasks/test-bdd | 5 + .config/mise/tasks/typecheck | 9 + .github/workflows/ci.yml | 109 +++++++ .github/workflows/release.yml | 97 ++++++ .gitignore | 79 ++++- .pre-commit-config.yaml | 27 ++ AGENTS.md | 297 ++++++++++++++++++ README.md | 133 ++++++-- behave.ini | 5 + features/environment.py | 69 ++++ features/morphir_setup.feature | 21 ++ features/steps/__init__.py | 1 + features/steps/setup_steps.py | 56 ++++ packages/morphir-tools/README.md | 44 +++ packages/morphir-tools/pyproject.toml | 43 +++ .../src/morphir_tools/__init__.py | 13 + .../morphir-tools/src/morphir_tools/py.typed | 0 packages/morphir/README.md | 50 +++ packages/morphir/pyproject.toml | 36 +++ packages/morphir/src/morphir/__init__.py | 14 + packages/morphir/src/morphir/ir/__init__.py | 12 + packages/morphir/src/morphir/py.typed | 0 pyproject.toml | 141 +++++++++ tests/__init__.py | 1 + tests/conftest.py | 9 + tests/tools/__init__.py | 1 + tests/tools/test_tools.py | 26 ++ tests/unit/__init__.py | 1 + tests/unit/test_morphir.py | 43 +++ 40 files changed, 1465 insertions(+), 36 deletions(-) create mode 100644 .agents/skills/README.md create mode 100644 .config/mise/config.toml create mode 100755 .config/mise/tasks/build create mode 100755 .config/mise/tasks/check create mode 100755 .config/mise/tasks/clean create mode 100755 .config/mise/tasks/coverage create mode 100755 .config/mise/tasks/format create mode 100755 .config/mise/tasks/format-check create mode 100755 .config/mise/tasks/lint create mode 100755 .config/mise/tasks/test create mode 100755 .config/mise/tasks/test-all create mode 100755 .config/mise/tasks/test-bdd create mode 100755 .config/mise/tasks/typecheck create mode 100644 .github/workflows/ci.yml create mode 100644 .github/workflows/release.yml create mode 100644 .pre-commit-config.yaml create mode 100644 AGENTS.md create mode 100644 behave.ini create mode 100644 features/environment.py create mode 100644 features/morphir_setup.feature create mode 100644 features/steps/__init__.py create mode 100644 features/steps/setup_steps.py create mode 100644 packages/morphir-tools/README.md create mode 100644 packages/morphir-tools/pyproject.toml create mode 100644 packages/morphir-tools/src/morphir_tools/__init__.py create mode 100644 packages/morphir-tools/src/morphir_tools/py.typed create mode 100644 packages/morphir/README.md create mode 100644 packages/morphir/pyproject.toml create mode 100644 packages/morphir/src/morphir/__init__.py create mode 100644 packages/morphir/src/morphir/ir/__init__.py create mode 100644 packages/morphir/src/morphir/py.typed create mode 100644 pyproject.toml create mode 100644 tests/__init__.py create mode 100644 tests/conftest.py create mode 100644 tests/tools/__init__.py create mode 100644 tests/tools/test_tools.py create mode 100644 tests/unit/__init__.py create mode 100644 tests/unit/test_morphir.py diff --git a/.agents/skills/README.md b/.agents/skills/README.md new file mode 100644 index 00000000..9c118ba0 --- /dev/null +++ b/.agents/skills/README.md @@ -0,0 +1,85 @@ +# Agent Skills + +This directory contains agentic skills for the Morphir Python project, following the [Agent Skills Specification](https://agentskills.io/). + +## What are Agent Skills? + +Agent Skills are folders of instructions, scripts, and resources that AI agents can discover and use to perform tasks more accurately and efficiently. They provide a simple, open format for extending agent capabilities with: + +- **Procedural knowledge** - Step-by-step instructions for complex tasks +- **Contextual information** - Project-specific knowledge +- **Scripts** - Executable code for common operations +- **References** - Additional documentation + +## Directory Structure + +Each skill should be in its own subdirectory with a `SKILL.md` file: + +``` +.agents/skills/ +├── README.md # This file +├── skill-name/ +│ ├── SKILL.md # Required - skill definition +│ ├── scripts/ # Optional - executable scripts +│ ├── references/ # Optional - additional docs +│ └── assets/ # Optional - templates, data files +└── another-skill/ + └── SKILL.md +``` + +## SKILL.md Format + +Each skill must have a `SKILL.md` file with YAML frontmatter: + +```yaml +--- +name: skill-name +description: A description of what this skill does and when to use it. +license: Apache-2.0 +compatibility: Requirements (e.g., "Requires Python 3.14+") +metadata: + author: finos + version: "1.0" +--- + +# Skill Instructions + +Step-by-step instructions for the skill... +``` + +### Required Fields + +| Field | Description | +|-------|-------------| +| `name` | Lowercase, hyphenated name (must match directory name) | +| `description` | What the skill does and when to use it (max 1024 chars) | + +### Optional Fields + +| Field | Description | +|-------|-------------| +| `license` | License for the skill | +| `compatibility` | Environment requirements | +| `metadata` | Additional key-value metadata | +| `allowed-tools` | Pre-approved tools for the skill | + +## Creating a New Skill + +1. Create a directory with your skill name (lowercase, hyphenated) +2. Add a `SKILL.md` file with the required frontmatter +3. Add any supporting scripts, references, or assets +4. Test the skill with an agent to verify it works correctly + +## Validation + +Use the reference library to validate skills: + +```bash +npx skills-ref validate ./skill-name +``` + +## Resources + +- [Agent Skills Specification](https://agentskills.io/specification) +- [Example Skills](https://github.com/anthropics/skills) +- [Reference Library](https://github.com/agentskills/agentskills/tree/main/skills-ref) diff --git a/.config/mise/config.toml b/.config/mise/config.toml new file mode 100644 index 00000000..a61de704 --- /dev/null +++ b/.config/mise/config.toml @@ -0,0 +1,9 @@ +[tools] +python = "3.14" +uv = "latest" + +[env] +VIRTUAL_ENV = "{{config_root}}/.venv" + +[settings] +experimental = true diff --git a/.config/mise/tasks/build b/.config/mise/tasks/build new file mode 100755 index 00000000..7596b6e6 --- /dev/null +++ b/.config/mise/tasks/build @@ -0,0 +1,11 @@ +#!/usr/bin/env bash +#MISE description="Build all packages" +set -euo pipefail + +echo "Building morphir package..." +uv build packages/morphir + +echo "Building morphir-tools package..." +uv build packages/morphir-tools + +echo "Build complete!" diff --git a/.config/mise/tasks/check b/.config/mise/tasks/check new file mode 100755 index 00000000..8b0090d0 --- /dev/null +++ b/.config/mise/tasks/check @@ -0,0 +1,6 @@ +#!/usr/bin/env bash +#MISE description="Run all checks (lint, format, typecheck, tests)" +#MISE depends=["lint", "format-check", "typecheck", "test-all"] +set -euo pipefail + +echo "All checks passed!" diff --git a/.config/mise/tasks/clean b/.config/mise/tasks/clean new file mode 100755 index 00000000..a15b0d5d --- /dev/null +++ b/.config/mise/tasks/clean @@ -0,0 +1,17 @@ +#!/usr/bin/env bash +#MISE description="Clean build artifacts and caches" +set -euo pipefail + +echo "Cleaning build artifacts..." +rm -rf build/ dist/ .eggs/ +find . -type d -name "*.egg-info" -exec rm -rf {} + 2>/dev/null || true +find . -type d -name "__pycache__" -exec rm -rf {} + 2>/dev/null || true +find . -type f -name "*.py[cod]" -delete 2>/dev/null || true + +echo "Cleaning test artifacts..." +rm -rf .pytest_cache/ .coverage htmlcov/ coverage.xml .hypothesis/ + +echo "Cleaning type checker caches..." +rm -rf .mypy_cache/ .ruff_cache/ .pyright/ + +echo "Clean complete!" diff --git a/.config/mise/tasks/coverage b/.config/mise/tasks/coverage new file mode 100755 index 00000000..dbc4961c --- /dev/null +++ b/.config/mise/tasks/coverage @@ -0,0 +1,5 @@ +#!/usr/bin/env bash +#MISE description="Run tests with coverage report" +set -euo pipefail + +uv run pytest tests/ --cov=packages/morphir/src --cov=packages/morphir-tools/src --cov-report=term-missing --cov-report=html diff --git a/.config/mise/tasks/format b/.config/mise/tasks/format new file mode 100755 index 00000000..b1e439f1 --- /dev/null +++ b/.config/mise/tasks/format @@ -0,0 +1,5 @@ +#!/usr/bin/env bash +#MISE description="Run ruff formatter on the codebase" +set -euo pipefail + +uv run ruff format . diff --git a/.config/mise/tasks/format-check b/.config/mise/tasks/format-check new file mode 100755 index 00000000..b6ce1373 --- /dev/null +++ b/.config/mise/tasks/format-check @@ -0,0 +1,5 @@ +#!/usr/bin/env bash +#MISE description="Check code formatting without making changes" +set -euo pipefail + +uv run ruff format --check . diff --git a/.config/mise/tasks/lint b/.config/mise/tasks/lint new file mode 100755 index 00000000..78f73060 --- /dev/null +++ b/.config/mise/tasks/lint @@ -0,0 +1,5 @@ +#!/usr/bin/env bash +#MISE description="Run ruff linter on the codebase" +set -euo pipefail + +uv run ruff check . diff --git a/.config/mise/tasks/test b/.config/mise/tasks/test new file mode 100755 index 00000000..c4cf465d --- /dev/null +++ b/.config/mise/tasks/test @@ -0,0 +1,5 @@ +#!/usr/bin/env bash +#MISE description="Run pytest unit tests" +set -euo pipefail + +uv run pytest tests/ diff --git a/.config/mise/tasks/test-all b/.config/mise/tasks/test-all new file mode 100755 index 00000000..c5484d4d --- /dev/null +++ b/.config/mise/tasks/test-all @@ -0,0 +1,6 @@ +#!/usr/bin/env bash +#MISE description="Run all tests (unit and BDD)" +#MISE depends=["test", "test-bdd"] +set -euo pipefail + +echo "All tests completed successfully!" diff --git a/.config/mise/tasks/test-bdd b/.config/mise/tasks/test-bdd new file mode 100755 index 00000000..ddc0de67 --- /dev/null +++ b/.config/mise/tasks/test-bdd @@ -0,0 +1,5 @@ +#!/usr/bin/env bash +#MISE description="Run behave BDD tests" +set -euo pipefail + +uv run behave features/ diff --git a/.config/mise/tasks/typecheck b/.config/mise/tasks/typecheck new file mode 100755 index 00000000..5e8fe8ce --- /dev/null +++ b/.config/mise/tasks/typecheck @@ -0,0 +1,9 @@ +#!/usr/bin/env bash +#MISE description="Run mypy and pyright type checkers" +set -euo pipefail + +echo "Running mypy..." +uv run mypy packages/morphir/src packages/morphir-tools/src + +echo "Running pyright..." +uv run pyright packages/morphir/src packages/morphir-tools/src diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 00000000..1be90b61 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,109 @@ +name: CI + +on: + push: + branches: [main] + pull_request: + branches: [main] + +permissions: + contents: read + +jobs: + lint: + name: Lint + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Set up uv + uses: astral-sh/setup-uv@v4 + with: + enable-cache: true + + - name: Install dependencies + run: uv sync --group dev + + - name: Run ruff linter + run: uv run ruff check . + + - name: Check formatting + run: uv run ruff format --check . + + typecheck: + name: Type Check + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Set up uv + uses: astral-sh/setup-uv@v4 + with: + enable-cache: true + + - name: Install dependencies + run: uv sync --group dev + + - name: Run mypy + run: uv run mypy packages/morphir/src packages/morphir-tools/src + + - name: Run pyright + run: uv run pyright packages/morphir/src packages/morphir-tools/src + + test: + name: Test + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Set up uv + uses: astral-sh/setup-uv@v4 + with: + enable-cache: true + + - name: Install dependencies + run: uv sync --group test + + - name: Run pytest + run: uv run pytest tests/ --cov=packages/morphir/src --cov=packages/morphir-tools/src --cov-report=xml + + - name: Run behave + run: uv run behave features/ + + - name: Upload coverage to Codecov + uses: codecov/codecov-action@v4 + with: + files: ./coverage.xml + fail_ci_if_error: false + env: + CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} + + build: + name: Build + runs-on: ubuntu-latest + needs: [lint, typecheck, test] + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Set up uv + uses: astral-sh/setup-uv@v4 + with: + enable-cache: true + + - name: Build morphir package + run: uv build packages/morphir + + - name: Build morphir-tools package + run: uv build packages/morphir-tools + + - name: Upload artifacts + uses: actions/upload-artifact@v4 + with: + name: dist + path: | + packages/morphir/dist/ + packages/morphir-tools/dist/ diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 00000000..e83d4734 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,97 @@ +name: Release + +on: + push: + tags: + - 'v*' + +permissions: + contents: write + id-token: write + +jobs: + build: + name: Build packages + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Set up uv + uses: astral-sh/setup-uv@v4 + with: + enable-cache: true + + - name: Build morphir package + run: uv build packages/morphir + + - name: Build morphir-tools package + run: uv build packages/morphir-tools + + - name: Upload morphir dist + uses: actions/upload-artifact@v4 + with: + name: morphir-dist + path: packages/morphir/dist/ + + - name: Upload morphir-tools dist + uses: actions/upload-artifact@v4 + with: + name: morphir-tools-dist + path: packages/morphir-tools/dist/ + + publish-morphir: + name: Publish morphir to PyPI + needs: build + runs-on: ubuntu-latest + environment: + name: pypi + url: https://pypi.org/project/morphir/ + steps: + - name: Download morphir dist + uses: actions/download-artifact@v4 + with: + name: morphir-dist + path: dist/ + + - name: Publish to PyPI + uses: pypa/gh-action-pypi-publish@release/v1 + + publish-morphir-tools: + name: Publish morphir-tools to PyPI + needs: [build, publish-morphir] + runs-on: ubuntu-latest + environment: + name: pypi + url: https://pypi.org/project/morphir-tools/ + steps: + - name: Download morphir-tools dist + uses: actions/download-artifact@v4 + with: + name: morphir-tools-dist + path: dist/ + + - name: Publish to PyPI + uses: pypa/gh-action-pypi-publish@release/v1 + + github-release: + name: Create GitHub Release + needs: [publish-morphir, publish-morphir-tools] + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Download all artifacts + uses: actions/download-artifact@v4 + with: + path: dist/ + merge-multiple: true + + - name: Create GitHub Release + uses: softprops/action-gh-release@v2 + with: + files: dist/* + generate_release_notes: true + draft: false + prerelease: ${{ contains(github.ref, 'alpha') || contains(github.ref, 'beta') || contains(github.ref, 'rc') }} diff --git a/.gitignore b/.gitignore index a4e674d3..9ef9dd6f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,20 +1,69 @@ -# dependencies -website/node_modules +# Python +__pycache__/ +*.py[cod] +*$py.class +*.so +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +*.egg-info/ +.installed.cfg +*.egg -# production -website/build +# Virtual environments +.venv/ +venv/ +ENV/ +env/ -# generated files -website/.docusaurus -.cache-loader +# IDE +.idea/ +.vscode/ +*.swp +*.swo +*~ -# misc -.DS_Store +# Type checkers +.mypy_cache/ +.pyright/ +.ruff_cache/ + +# Testing +.pytest_cache/ +.coverage +htmlcov/ +coverage.xml +*.cover +.hypothesis/ + +# Build artifacts +*.manifest +*.spec + +# Environments +.env .env.local -.env.development.local -.env.test.local -.env.production.local +.env.*.local + +# Misc +.DS_Store +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# uv +uv.lock -website/npm-debug.log* -website/yarn-debug.log* -website/yarn-error.log* \ No newline at end of file +# mise +.mise.local.toml diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 00000000..fa000028 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,27 @@ +repos: + - repo: https://github.com/astral-sh/ruff-pre-commit + rev: v0.8.6 + hooks: + - id: ruff + args: [--fix] + - id: ruff-format + + - repo: https://github.com/pre-commit/mirrors-mypy + rev: v1.14.1 + hooks: + - id: mypy + additional_dependencies: [] + args: [--config-file=pyproject.toml] + pass_filenames: false + entry: mypy packages/morphir/src packages/morphir-tools/src + + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v5.0.0 + hooks: + - id: trailing-whitespace + - id: end-of-file-fixer + - id: check-yaml + - id: check-toml + - id: check-added-large-files + - id: check-merge-conflict + - id: debug-statements diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 00000000..f041a321 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,297 @@ +# Agent Guidelines for Morphir Python + +This document provides guidelines for AI code agents working on the Morphir Python codebase. + +## Project Overview + +Morphir Python is a port of Morphir to Python, providing functional domain modeling capabilities. The project follows functional programming principles while maintaining Pythonic usability. + +## Monorepo Structure + +``` +morphir-python/ +├── packages/ +│ ├── morphir/ # Core library - IR models, types, pure functions +│ └── morphir-tools/ # CLI tools and extensions (depends on morphir) +├── tests/ +│ ├── unit/ # Unit tests for morphir package +│ └── tools/ # Unit tests for morphir-tools package +└── features/ # BDD feature tests (behave) +``` + +### Package Responsibilities + +**`morphir` (core library)** +- Morphir IR (Intermediate Representation) models +- Type definitions and type algebra +- Pure functional primitives +- Zero CLI or IO dependencies +- Should be usable as a standalone library + +**`morphir-tools` (CLI/tools)** +- Command-line interface +- File I/O operations +- Code generation backends +- Depends on `morphir` core library + +## Coding Principles + +### 1. Functional Programming + +**Immutability by Default** + +Use frozen dataclasses for all data structures: + +```python +from dataclasses import dataclass + +@dataclass(frozen=True) +class Name: + """An immutable name consisting of parts.""" + parts: tuple[str, ...] +``` + +**Pure Functions** + +Functions should be pure - same inputs always produce same outputs with no side effects: + +```python +# Good: Pure function +def qualify(module_name: Name, local_name: Name) -> Name: + return Name(parts=module_name.parts + local_name.parts) + +# Bad: Side effect +def qualify(module_name: Name, local_name: Name) -> Name: + print(f"Qualifying {local_name}") # Side effect! + return Name(parts=module_name.parts + local_name.parts) +``` + +### 2. Algebraic Data Types (ADTs) + +Model domains using sum types (unions) and product types (dataclasses): + +```python +from dataclasses import dataclass +from typing import Union + +# Product type (AND) +@dataclass(frozen=True) +class FunctionType: + argument_type: "Type" + return_type: "Type" + +@dataclass(frozen=True) +class RecordType: + fields: tuple[tuple[str, "Type"], ...] + +@dataclass(frozen=True) +class UnitType: + pass + +# Sum type (OR) - Making illegal states unrepresentable +Type = Union[FunctionType, RecordType, UnitType] +``` + +### 3. Make Illegal States Unrepresentable + +Design types so that invalid states cannot be constructed: + +```python +# Bad: Allows invalid states +@dataclass +class User: + name: str | None + email: str | None + is_verified: bool # Can be True even if email is None! + +# Good: Invalid states are impossible +@dataclass(frozen=True) +class UnverifiedUser: + name: str + email: str + +@dataclass(frozen=True) +class VerifiedUser: + name: str + email: str + verified_at: datetime + +User = Union[UnverifiedUser, VerifiedUser] +``` + +### 4. Type Annotations + +All code must have complete type annotations. We use strict mode for both mypy and pyright. + +```python +from typing import TypeVar, Callable, Sequence + +T = TypeVar("T") +U = TypeVar("U") + +def map_list(func: Callable[[T], U], items: Sequence[T]) -> list[U]: + """Apply a function to each item in a sequence.""" + return [func(item) for item in items] +``` + +### 5. Pattern Matching + +Use structural pattern matching for handling sum types: + +```python +def type_to_string(t: Type) -> str: + match t: + case FunctionType(arg, ret): + return f"({type_to_string(arg)} -> {type_to_string(ret)})" + case RecordType(fields): + field_strs = [f"{name}: {type_to_string(typ)}" for name, typ in fields] + return f"{{ {', '.join(field_strs)} }}" + case UnitType(): + return "()" +``` + +## Code Style + +### Docstrings + +Use Google-style docstrings: + +```python +def process_type(type_def: Type, context: Context) -> Result[ProcessedType, Error]: + """Process a type definition within a context. + + Args: + type_def: The type definition to process. + context: The processing context containing scope information. + + Returns: + A Result containing either the processed type or an error. + + Raises: + ValueError: If the type definition is malformed. + """ +``` + +### Formatting + +- Use ruff for formatting (configured in pyproject.toml) +- Line length: 88 characters +- Double quotes for strings +- 4-space indentation + +## Testing + +### TDD Workflow + +Follow red-green-refactor: + +1. **Red**: Write a failing test first +2. **Green**: Write minimal code to make it pass +3. **Refactor**: Clean up while keeping tests green + +### Unit Tests (pytest) + +```python +# tests/unit/test_name.py +import pytest +from morphir.ir import Name + +class TestName: + def test_from_string_splits_on_separators(self) -> None: + name = Name.from_string("hello.world") + assert name.parts == ("hello", "world") + + def test_to_string_joins_with_dot(self) -> None: + name = Name(parts=("hello", "world")) + assert name.to_string() == "hello.world" +``` + +### BDD Tests (behave) + +Write behavior-driven scenarios for user-facing features: + +```gherkin +# features/type_checking.feature +Feature: Type Checking + As a developer + I want type checking for my domain models + So that I catch errors at compile time + + Scenario: Function type matches argument + Given a function type from Int to String + And a value of type Int + When I apply the function to the value + Then the result type should be String +``` + +### Test Coverage + +- Minimum 80% coverage required +- All public APIs must have tests +- Edge cases and error conditions must be tested + +## Development Commands + +```bash +# Run all checks +mise run check + +# Individual commands +mise run lint # Linting +mise run format # Format code +mise run typecheck # Type checking (mypy + pyright) +mise run test # Unit tests +mise run test-bdd # BDD tests +mise run coverage # Coverage report +``` + +## Git Workflow + +1. Create feature branch from main +2. Make changes following TDD +3. Ensure all checks pass: `mise run check` +4. Submit PR with clear description +5. Address review feedback + +## Dependencies + +When adding dependencies: + +- **morphir package**: Should have minimal/zero dependencies +- **morphir-tools package**: Can have CLI and IO dependencies +- Always pin minimum versions in pyproject.toml + +## Error Handling + +Use Result types instead of exceptions where appropriate: + +```python +from dataclasses import dataclass +from typing import TypeVar, Union + +T = TypeVar("T") +E = TypeVar("E") + +@dataclass(frozen=True) +class Ok[T]: + value: T + +@dataclass(frozen=True) +class Err[E]: + error: E + +Result = Union[Ok[T], Err[E]] +``` + +## Performance Considerations + +- Use `tuple` instead of `list` for immutable sequences +- Use `frozenset` instead of `set` for immutable sets +- Consider `__slots__` for frequently instantiated classes +- Profile before optimizing + +## Documentation + +- All public APIs must have docstrings +- Keep README.md up to date +- Document non-obvious design decisions in code comments diff --git a/README.md b/README.md index 68894210..d7b4eace 100644 --- a/README.md +++ b/README.md @@ -1,51 +1,136 @@ [![FINOS - Incubating](https://cdn.jsdelivr.net/gh/finos/contrib-toolbox@master/images/badge-incubating.svg)](https://community.finos.org/docs/governance/Software-Projects/stages/incubating) +[![CI](https://github.com/finos/morphir-python/actions/workflows/ci.yml/badge.svg)](https://github.com/finos/morphir-python/actions/workflows/ci.yml) # Morphir Python -Short blurb about what your project does. +Python port of [Morphir](https://morphir.finos.org) - a library of tools for building and working with functional domain models. + +Morphir enables you to write business logic once and use it across multiple platforms, languages, and runtimes. It provides a strongly-typed intermediate representation (IR) that captures the semantics of your domain model. + +## Packages + +This monorepo contains two packages: + +| Package | Description | PyPI | +|---------|-------------|------| +| `morphir` | Core library - IR models, types, and functional domain modeling primitives | [![PyPI](https://img.shields.io/pypi/v/morphir)](https://pypi.org/project/morphir/) | +| `morphir-tools` | CLI tools and extensions for working with Morphir | [![PyPI](https://img.shields.io/pypi/v/morphir-tools)](https://pypi.org/project/morphir-tools/) | ## Installation -OS X & Linux: +### Library Only + +If you just need the Morphir library for your Python project: -```sh -npm install my-crazy-module --save +```bash +pip install morphir ``` -Windows: +Or with uv: -```sh -edit autoexec.bat +```bash +uv add morphir ``` -## Usage example +### With CLI Tools -A few motivating and useful examples of how your project can be used. Spice this up with code blocks and potentially screenshots / videos ([LiceCap](https://www.cockos.com/licecap/) is great for this kind of thing). +For the full toolset including CLI commands: -_For more examples and usage, please refer to the [Wiki][wiki]._ +```bash +pip install morphir-tools +``` + +Or with uv: -## Development setup +```bash +uv add morphir-tools +``` -Describe how to install all development dependencies and how to run an automated test-suite of some kind. Potentially do this for multiple platforms. +## Quick Start -```sh -make install -npm test +```python +from morphir.ir import Type, Value + +# Example usage will be added as the library develops ``` -## Roadmap +## Requirements -List the roadmap steps; alternatively link the Confluence Wiki page where the project roadmap is published. +- Python 3.14+ -1. Item 1 -2. Item 2 -3. .... +## Development Setup + +This project uses [mise](https://mise.jdx.dev/) for tool management and [uv](https://docs.astral.sh/uv/) for Python package management. + +### Prerequisites + +Install mise (if not already installed): + +```bash +curl https://mise.run | sh +``` + +### Setup + +1. Clone the repository: + +```bash +git clone https://github.com/finos/morphir-python.git +cd morphir-python +``` + +2. Install tools and dependencies: + +```bash +mise install +uv sync --all-groups +``` + +3. Run the checks: + +```bash +mise run check +``` + +### Available Tasks + +| Task | Description | +|------|-------------| +| `mise run lint` | Run ruff linter | +| `mise run format` | Run ruff formatter | +| `mise run typecheck` | Run mypy and pyright | +| `mise run test` | Run pytest unit tests | +| `mise run test-bdd` | Run behave BDD tests | +| `mise run test-all` | Run all tests | +| `mise run coverage` | Run tests with coverage | +| `mise run check` | Run all checks | +| `mise run build` | Build packages | +| `mise run clean` | Clean build artifacts | + +## Project Principles + +This project follows functional programming principles: + +- **Immutability**: Data structures are immutable by default +- **Type Safety**: Strict type annotations with mypy and pyright +- **Algebraic Data Types**: Using `@dataclass(frozen=True)`, Unions, and Protocols +- **Making Illegal States Unrepresentable**: Domain modeling that prevents invalid states at compile time + +## Roadmap + +1. Core IR model implementation +2. JSON serialization/deserialization +3. Type checking and validation +4. Code generation backends +5. CLI tooling ## Contributing -For any questions, bugs or feature requests please open an [issue](https://github.com/finos/morphir-python/issues) + +For any questions, bugs or feature requests please open an [issue](https://github.com/finos/morphir-python/issues). For anything else please send an email to morphir@finos.org. To submit a contribution: + 1. Fork it () 2. Create your feature branch (`git checkout -b feature/fooBar`) 3. Read our [contribution guidelines](.github/CONTRIBUTING.md) and [Community Code of Conduct](https://www.finos.org/code-of-conduct) @@ -57,6 +142,12 @@ _NOTE:_ Commits and pull requests to FINOS repositories will only be accepted fr *Need an ICLA? Unsure if you are covered under an existing CCLA? Email [help@finos.org](mailto:help@finos.org)* +## Related Projects + +- [Morphir](https://github.com/finos/morphir) - The main Morphir project +- [Morphir Elm](https://github.com/finos/morphir-elm) - Elm implementation +- [Morphir Scala](https://github.com/finos/morphir-scala) - Scala implementation + ## License Copyright 2026 FINOS diff --git a/behave.ini b/behave.ini new file mode 100644 index 00000000..2550cee9 --- /dev/null +++ b/behave.ini @@ -0,0 +1,5 @@ +[behave] +paths = features +format = pretty +show_timings = true +color = true diff --git a/features/environment.py b/features/environment.py new file mode 100644 index 00000000..11583fa6 --- /dev/null +++ b/features/environment.py @@ -0,0 +1,69 @@ +"""Behave environment configuration and hooks. + +This module contains hooks that run before and after various stages of +the BDD test execution lifecycle. +""" + +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + from behave.runner import Context + + +def before_all(context: Context) -> None: + """Run before all tests. + + Args: + context: The behave context object. + """ + # Add any global setup here + context.config.setup_logging() + + +def before_feature(context: Context, feature: object) -> None: + """Run before each feature. + + Args: + context: The behave context object. + feature: The feature being executed. + """ + pass + + +def before_scenario(context: Context, scenario: object) -> None: + """Run before each scenario. + + Args: + context: The behave context object. + scenario: The scenario being executed. + """ + pass + + +def after_scenario(context: Context, scenario: object) -> None: + """Run after each scenario. + + Args: + context: The behave context object. + scenario: The scenario that was executed. + """ + pass + + +def after_feature(context: Context, feature: object) -> None: + """Run after each feature. + + Args: + context: The behave context object. + feature: The feature that was executed. + """ + pass + + +def after_all(context: Context) -> None: + """Run after all tests. + + Args: + context: The behave context object. + """ + pass diff --git a/features/morphir_setup.feature b/features/morphir_setup.feature new file mode 100644 index 00000000..99282d92 --- /dev/null +++ b/features/morphir_setup.feature @@ -0,0 +1,21 @@ +Feature: Morphir Python Setup + As a developer + I want to verify the project is set up correctly + So that I can start developing Morphir features + + Scenario: Morphir core library can be imported + Given the Python environment is set up + When I import the morphir module + Then the module should be available + And it should have a version attribute + + Scenario: Morphir tools can be imported + Given the Python environment is set up + When I import the morphir_tools module + Then the module should be available + And it should have a version attribute + + Scenario: Morphir IR module can be imported + Given the Python environment is set up + When I import the morphir.ir module + Then the module should be available diff --git a/features/steps/__init__.py b/features/steps/__init__.py new file mode 100644 index 00000000..2a8bff71 --- /dev/null +++ b/features/steps/__init__.py @@ -0,0 +1 @@ +"""Step definitions for Morphir BDD tests.""" diff --git a/features/steps/setup_steps.py b/features/steps/setup_steps.py new file mode 100644 index 00000000..57617d2d --- /dev/null +++ b/features/steps/setup_steps.py @@ -0,0 +1,56 @@ +"""Step definitions for project setup verification.""" + +from typing import TYPE_CHECKING, Any + +from behave import given, then, when + +if TYPE_CHECKING: + from behave.runner import Context + + +@given("the Python environment is set up") +def step_python_environment_setup(context: Context) -> None: + """Verify Python environment is available.""" + import sys + + context.python_version = sys.version_info + assert context.python_version >= (3, 14), "Python 3.14+ is required" + + +@when("I import the morphir module") +def step_import_morphir(context: Context) -> None: + """Import the morphir module.""" + import morphir + + context.module = morphir + + +@when("I import the morphir_tools module") +def step_import_morphir_tools(context: Context) -> None: + """Import the morphir_tools module.""" + import morphir_tools + + context.module = morphir_tools + + +@when("I import the morphir.ir module") +def step_import_morphir_ir(context: Context) -> None: + """Import the morphir.ir module.""" + from morphir import ir + + context.module = ir + + +@then("the module should be available") +def step_module_available(context: Context) -> None: + """Verify the module was imported successfully.""" + assert context.module is not None + + +@then("it should have a version attribute") +def step_has_version(context: Context) -> None: + """Verify the module has a __version__ attribute.""" + assert hasattr(context.module, "__version__") + version: Any = context.module.__version__ + assert isinstance(version, str) + assert len(version) > 0 diff --git a/packages/morphir-tools/README.md b/packages/morphir-tools/README.md new file mode 100644 index 00000000..7f478296 --- /dev/null +++ b/packages/morphir-tools/README.md @@ -0,0 +1,44 @@ +# Morphir Tools + +CLI tools and extensions for [Morphir Python](https://github.com/finos/morphir-python). + +This package provides: + +- Command-line interface for Morphir operations +- Code generation backends +- File I/O utilities +- Development tools + +## Installation + +```bash +pip install morphir-tools +``` + +Or with uv: + +```bash +uv add morphir-tools +``` + +This will also install the `morphir` core library as a dependency. + +## Usage + +```bash +# CLI commands will be added as features are implemented +morphir --help +``` + +## Requirements + +- Python 3.14+ +- morphir (core library) + +## License + +Apache-2.0 - see the [LICENSE](../../LICENSE) file for details. + +## Related Packages + +- [morphir](https://pypi.org/project/morphir/) - Core library diff --git a/packages/morphir-tools/pyproject.toml b/packages/morphir-tools/pyproject.toml new file mode 100644 index 00000000..b89fd815 --- /dev/null +++ b/packages/morphir-tools/pyproject.toml @@ -0,0 +1,43 @@ +[project] +name = "morphir-tools" +version = "0.1.0" +description = "CLI tools and extensions for Morphir Python" +readme = "README.md" +license = "Apache-2.0" +requires-python = ">=3.14" +keywords = ["morphir", "cli", "tools", "code-generation", "domain-modeling"] +classifiers = [ + "Development Status :: 3 - Alpha", + "Environment :: Console", + "Intended Audience :: Developers", + "License :: OSI Approved :: Apache Software License", + "Operating System :: OS Independent", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.14", + "Topic :: Software Development :: Code Generators", + "Topic :: Software Development :: Libraries", + "Typing :: Typed", +] +authors = [ + { name = "FINOS", email = "morphir@finos.org" } +] +dependencies = [ + "morphir>=0.1.0", +] + +[project.urls] +Homepage = "https://github.com/finos/morphir-python" +Documentation = "https://morphir.finos.org" +Repository = "https://github.com/finos/morphir-python" +Issues = "https://github.com/finos/morphir-python/issues" + +[project.scripts] +# CLI entry points will be added here as features are implemented +# morphir = "morphir_tools.cli:main" + +[build-system] +requires = ["hatchling"] +build-backend = "hatchling.build" + +[tool.hatch.build.targets.wheel] +packages = ["src/morphir_tools"] diff --git a/packages/morphir-tools/src/morphir_tools/__init__.py b/packages/morphir-tools/src/morphir_tools/__init__.py new file mode 100644 index 00000000..4b4d52d8 --- /dev/null +++ b/packages/morphir-tools/src/morphir_tools/__init__.py @@ -0,0 +1,13 @@ +"""Morphir Tools - CLI tools and extensions for Morphir Python. + +This package provides command-line tools and utilities for working with +Morphir domain models, including code generation and development tools. + +Example: + >>> import morphir_tools + >>> morphir_tools.__version__ + '0.1.0' +""" + +__version__ = "0.1.0" +__all__ = ["__version__"] diff --git a/packages/morphir-tools/src/morphir_tools/py.typed b/packages/morphir-tools/src/morphir_tools/py.typed new file mode 100644 index 00000000..e69de29b diff --git a/packages/morphir/README.md b/packages/morphir/README.md new file mode 100644 index 00000000..c3545d9d --- /dev/null +++ b/packages/morphir/README.md @@ -0,0 +1,50 @@ +# Morphir + +Python port of [Morphir](https://morphir.finos.org) - functional domain modeling for the enterprise. + +This is the core library package containing: + +- Morphir IR (Intermediate Representation) models +- Type definitions and type algebra +- Pure functional primitives + +## Installation + +```bash +pip install morphir +``` + +Or with uv: + +```bash +uv add morphir +``` + +## Usage + +```python +from morphir.ir import Type, Value + +# Example usage will be added as the library develops +``` + +## Requirements + +- Python 3.14+ + +## Design Principles + +This library follows functional programming principles: + +- **Immutability**: All data structures are immutable (frozen dataclasses) +- **Type Safety**: Complete type annotations with strict mypy/pyright checking +- **Algebraic Data Types**: Using unions and frozen dataclasses +- **Making Illegal States Unrepresentable**: Domain modeling prevents invalid states + +## License + +Apache-2.0 - see the [LICENSE](../../LICENSE) file for details. + +## Related Packages + +- [morphir-tools](https://pypi.org/project/morphir-tools/) - CLI tools and extensions diff --git a/packages/morphir/pyproject.toml b/packages/morphir/pyproject.toml new file mode 100644 index 00000000..5e67c9b2 --- /dev/null +++ b/packages/morphir/pyproject.toml @@ -0,0 +1,36 @@ +[project] +name = "morphir" +version = "0.1.0" +description = "Python port of Morphir - functional domain modeling for the enterprise" +readme = "README.md" +license = "Apache-2.0" +requires-python = ">=3.14" +keywords = ["morphir", "domain-modeling", "functional", "dsl", "type-safe", "ir"] +classifiers = [ + "Development Status :: 3 - Alpha", + "Intended Audience :: Developers", + "License :: OSI Approved :: Apache Software License", + "Operating System :: OS Independent", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.14", + "Topic :: Software Development :: Libraries", + "Topic :: Software Development :: Libraries :: Python Modules", + "Typing :: Typed", +] +authors = [ + { name = "FINOS", email = "morphir@finos.org" } +] +dependencies = [] + +[project.urls] +Homepage = "https://github.com/finos/morphir-python" +Documentation = "https://morphir.finos.org" +Repository = "https://github.com/finos/morphir-python" +Issues = "https://github.com/finos/morphir-python/issues" + +[build-system] +requires = ["hatchling"] +build-backend = "hatchling.build" + +[tool.hatch.build.targets.wheel] +packages = ["src/morphir"] diff --git a/packages/morphir/src/morphir/__init__.py b/packages/morphir/src/morphir/__init__.py new file mode 100644 index 00000000..8074c7d1 --- /dev/null +++ b/packages/morphir/src/morphir/__init__.py @@ -0,0 +1,14 @@ +"""Morphir - Functional domain modeling for Python. + +Morphir enables you to write business logic once and use it across multiple +platforms, languages, and runtimes. It provides a strongly-typed intermediate +representation (IR) that captures the semantics of your domain model. + +Example: + >>> import morphir + >>> morphir.__version__ + '0.1.0' +""" + +__version__ = "0.1.0" +__all__ = ["__version__"] diff --git a/packages/morphir/src/morphir/ir/__init__.py b/packages/morphir/src/morphir/ir/__init__.py new file mode 100644 index 00000000..a9d83fca --- /dev/null +++ b/packages/morphir/src/morphir/ir/__init__.py @@ -0,0 +1,12 @@ +"""Morphir Intermediate Representation (IR) models. + +This module contains the core IR types that represent Morphir's type-safe +domain modeling primitives. The IR serves as the canonical representation +of domain models that can be transformed into various target languages. + +Note: + This module is currently a placeholder. The full IR implementation + will be added in subsequent development phases. +""" + +__all__: list[str] = [] diff --git a/packages/morphir/src/morphir/py.typed b/packages/morphir/src/morphir/py.typed new file mode 100644 index 00000000..e69de29b diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 00000000..516b5fec --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,141 @@ +[project] +name = "morphir-workspace" +version = "0.1.0" +description = "Morphir Python monorepo workspace" +requires-python = ">=3.14" +readme = "README.md" +license = "Apache-2.0" + +[dependency-groups] +dev = [ + "ruff>=0.8", + "mypy>=1.13", + "pyright>=1.1", + "pre-commit>=4.0", +] +test = [ + "pytest>=8.0", + "pytest-cov>=6.0", + "behave>=1.2", + "coverage>=7.0", +] + +[tool.uv] +managed = true + +[tool.uv.workspace] +members = ["packages/*"] + +[tool.uv.sources] +morphir = { workspace = true } + +# ============================================================================= +# Ruff Configuration +# ============================================================================= +[tool.ruff] +target-version = "py314" +line-length = 88 +exclude = [".venv", "build", "dist", ".git", "__pycache__"] + +[tool.ruff.lint] +select = [ + "E", "W", # pycodestyle + "F", # Pyflakes + "I", # isort + "N", # pep8-naming + "UP", # pyupgrade + "B", # flake8-bugbear + "C4", # flake8-comprehensions + "SIM", # flake8-simplify + "TCH", # flake8-type-checking + "RUF", # Ruff-specific + "D", # pydocstyle +] +ignore = [ + "D100", # Missing docstring in public module + "D104", # Missing docstring in public package + "D105", # Missing docstring in magic method + "D107", # Missing docstring in __init__ +] + +[tool.ruff.lint.pydocstyle] +convention = "google" + +[tool.ruff.lint.isort] +known-first-party = ["morphir", "morphir_tools"] + +[tool.ruff.format] +quote-style = "double" +indent-style = "space" +docstring-code-format = true + +# ============================================================================= +# Mypy Configuration +# ============================================================================= +[tool.mypy] +python_version = "3.14" +strict = true +warn_unreachable = true +pretty = true +show_error_codes = true +show_column_numbers = true +namespace_packages = true +explicit_package_bases = true +mypy_path = ["packages/morphir/src", "packages/morphir-tools/src"] + +[[tool.mypy.overrides]] +module = "tests.*" +disallow_untyped_defs = false +disallow_incomplete_defs = false + +[[tool.mypy.overrides]] +module = "features.*" +ignore_errors = true + +# ============================================================================= +# Pyright Configuration +# ============================================================================= +[tool.pyright] +pythonVersion = "3.14" +typeCheckingMode = "strict" +reportMissingImports = true +reportMissingTypeStubs = false +include = ["packages/morphir/src", "packages/morphir-tools/src", "tests"] +exclude = ["**/__pycache__", ".venv", "build", "dist"] + +# ============================================================================= +# Pytest Configuration +# ============================================================================= +[tool.pytest.ini_options] +testpaths = ["tests"] +python_files = ["test_*.py"] +python_classes = ["Test*"] +python_functions = ["test_*"] +addopts = "-v --tb=short" +filterwarnings = [ + "error", + "ignore::DeprecationWarning", +] + +# ============================================================================= +# Coverage Configuration +# ============================================================================= +[tool.coverage.run] +source = ["packages/morphir/src", "packages/morphir-tools/src"] +branch = true +omit = ["*/tests/*", "*/__pycache__/*", "*/.venv/*"] + +[tool.coverage.report] +exclude_lines = [ + "pragma: no cover", + "if TYPE_CHECKING:", + "@abstractmethod", + "@overload", + "raise NotImplementedError", +] +fail_under = 80 +show_missing = true +skip_covered = true + +[tool.coverage.html] +directory = "htmlcov" diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 00000000..0149bd65 --- /dev/null +++ b/tests/__init__.py @@ -0,0 +1 @@ +"""Test suite for Morphir Python packages.""" diff --git a/tests/conftest.py b/tests/conftest.py new file mode 100644 index 00000000..f95a2880 --- /dev/null +++ b/tests/conftest.py @@ -0,0 +1,9 @@ +"""Pytest configuration and shared fixtures for Morphir tests.""" + +import pytest + + +@pytest.fixture +def sample_version() -> str: + """Provide the expected version string for tests.""" + return "0.1.0" diff --git a/tests/tools/__init__.py b/tests/tools/__init__.py new file mode 100644 index 00000000..6b0f7375 --- /dev/null +++ b/tests/tools/__init__.py @@ -0,0 +1 @@ +"""Unit tests for the morphir-tools package.""" diff --git a/tests/tools/test_tools.py b/tests/tools/test_tools.py new file mode 100644 index 00000000..bc03a626 --- /dev/null +++ b/tests/tools/test_tools.py @@ -0,0 +1,26 @@ +"""Tests for the morphir-tools package.""" + +import morphir_tools + + +class TestMorphirToolsPackage: + """Tests for the morphir-tools package initialization.""" + + def test_version_is_defined(self) -> None: + """The package should have a version attribute.""" + assert hasattr(morphir_tools, "__version__") + + def test_version_matches_expected(self, sample_version: str) -> None: + """The version should match the expected value.""" + assert morphir_tools.__version__ == sample_version + + def test_version_is_string(self) -> None: + """The version should be a string.""" + assert isinstance(morphir_tools.__version__, str) + + def test_version_follows_semver(self) -> None: + """The version should follow semantic versioning format.""" + parts = morphir_tools.__version__.split(".") + assert len(parts) >= 2, "Version should have at least major.minor" + for part in parts: + assert part.isdigit() or "-" in part or "+" in part diff --git a/tests/unit/__init__.py b/tests/unit/__init__.py new file mode 100644 index 00000000..7d94e4ca --- /dev/null +++ b/tests/unit/__init__.py @@ -0,0 +1 @@ +"""Unit tests for the morphir core library.""" diff --git a/tests/unit/test_morphir.py b/tests/unit/test_morphir.py new file mode 100644 index 00000000..a8401d9d --- /dev/null +++ b/tests/unit/test_morphir.py @@ -0,0 +1,43 @@ +"""Tests for the morphir core library package.""" + +import morphir + + +class TestMorphirPackage: + """Tests for the morphir package initialization.""" + + def test_version_is_defined(self) -> None: + """The package should have a version attribute.""" + assert hasattr(morphir, "__version__") + + def test_version_matches_expected(self, sample_version: str) -> None: + """The version should match the expected value.""" + assert morphir.__version__ == sample_version + + def test_version_is_string(self) -> None: + """The version should be a string.""" + assert isinstance(morphir.__version__, str) + + def test_version_follows_semver(self) -> None: + """The version should follow semantic versioning format.""" + parts = morphir.__version__.split(".") + assert len(parts) >= 2, "Version should have at least major.minor" + for part in parts: + assert part.isdigit() or "-" in part or "+" in part + + +class TestMorphirIR: + """Tests for the morphir.ir submodule.""" + + def test_ir_module_is_importable(self) -> None: + """The ir submodule should be importable.""" + from morphir import ir + + assert ir is not None + + def test_ir_module_has_all(self) -> None: + """The ir submodule should have an __all__ attribute.""" + from morphir import ir + + assert hasattr(ir, "__all__") + assert isinstance(ir.__all__, list) From 44a92b5477141c05a2c7ccb5df2f0dbd887b691e Mon Sep 17 00:00:00 2001 From: Damian Reeves <957246+DamianReeves@users.noreply.github.com> Date: Mon, 19 Jan 2026 17:04:07 -0600 Subject: [PATCH 2/6] fix(ci): Add uv.lock for reproducible CI builds --- .gitignore | 3 - uv.lock | 464 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 464 insertions(+), 3 deletions(-) create mode 100644 uv.lock diff --git a/.gitignore b/.gitignore index 9ef9dd6f..7f6bcfa3 100644 --- a/.gitignore +++ b/.gitignore @@ -62,8 +62,5 @@ npm-debug.log* yarn-debug.log* yarn-error.log* -# uv -uv.lock - # mise .mise.local.toml diff --git a/uv.lock b/uv.lock new file mode 100644 index 00000000..b35647bb --- /dev/null +++ b/uv.lock @@ -0,0 +1,464 @@ +version = 1 +revision = 3 +requires-python = ">=3.14" + +[manifest] +members = [ + "morphir", + "morphir-tools", + "morphir-workspace", +] + +[[package]] +name = "behave" +version = "1.3.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama" }, + { name = "cucumber-expressions" }, + { name = "cucumber-tag-expressions" }, + { name = "parse" }, + { name = "parse-type" }, + { name = "six" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/62/51/f37442fe648b3e35ecf69bee803fa6db3f74c5b46d6c882d0bc5654185a2/behave-1.3.3.tar.gz", hash = "sha256:2b8f4b64ed2ea756a5a2a73e23defc1c4631e9e724c499e46661778453ebaf51", size = 892639, upload-time = "2025-09-04T12:12:02.531Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/63/71/06f74ffed6d74525c5cd6677c97bd2df0b7649e47a249cf6a0c2038083b2/behave-1.3.3-py2.py3-none-any.whl", hash = "sha256:89bdb62af8fb9f147ce245736a5de69f025e5edfb66f1fbe16c5007493f842c0", size = 223594, upload-time = "2025-09-04T12:12:00.3Z" }, +] + +[[package]] +name = "cfgv" +version = "3.5.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/4e/b5/721b8799b04bf9afe054a3899c6cf4e880fcf8563cc71c15610242490a0c/cfgv-3.5.0.tar.gz", hash = "sha256:d5b1034354820651caa73ede66a6294d6e95c1b00acc5e9b098e917404669132", size = 7334, upload-time = "2025-11-19T20:55:51.612Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/db/3c/33bac158f8ab7f89b2e59426d5fe2e4f63f7ed25df84c036890172b412b5/cfgv-3.5.0-py2.py3-none-any.whl", hash = "sha256:a8dc6b26ad22ff227d2634a65cb388215ce6cc96bbcc5cfde7641ae87e8dacc0", size = 7445, upload-time = "2025-11-19T20:55:50.744Z" }, +] + +[[package]] +name = "colorama" +version = "0.4.6" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697, upload-time = "2022-10-25T02:36:22.414Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" }, +] + +[[package]] +name = "coverage" +version = "7.13.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/23/f9/e92df5e07f3fc8d4c7f9a0f146ef75446bf870351cd37b788cf5897f8079/coverage-7.13.1.tar.gz", hash = "sha256:b7593fe7eb5feaa3fbb461ac79aac9f9fc0387a5ca8080b0c6fe2ca27b091afd", size = 825862, upload-time = "2025-12-28T15:42:56.969Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/aa/8e/ba0e597560c6563fc0adb902fda6526df5d4aa73bb10adf0574d03bd2206/coverage-7.13.1-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:97ab3647280d458a1f9adb85244e81587505a43c0c7cff851f5116cd2814b894", size = 218996, upload-time = "2025-12-28T15:42:04.978Z" }, + { url = "https://files.pythonhosted.org/packages/6b/8e/764c6e116f4221dc7aa26c4061181ff92edb9c799adae6433d18eeba7a14/coverage-7.13.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:8f572d989142e0908e6acf57ad1b9b86989ff057c006d13b76c146ec6a20216a", size = 219326, upload-time = "2025-12-28T15:42:06.691Z" }, + { url = "https://files.pythonhosted.org/packages/4f/a6/6130dc6d8da28cdcbb0f2bf8865aeca9b157622f7c0031e48c6cf9a0e591/coverage-7.13.1-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:d72140ccf8a147e94274024ff6fd8fb7811354cf7ef88b1f0a988ebaa5bc774f", size = 250374, upload-time = "2025-12-28T15:42:08.786Z" }, + { url = "https://files.pythonhosted.org/packages/82/2b/783ded568f7cd6b677762f780ad338bf4b4750205860c17c25f7c708995e/coverage-7.13.1-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:d3c9f051b028810f5a87c88e5d6e9af3c0ff32ef62763bf15d29f740453ca909", size = 252882, upload-time = "2025-12-28T15:42:10.515Z" }, + { url = "https://files.pythonhosted.org/packages/cd/b2/9808766d082e6a4d59eb0cc881a57fc1600eb2c5882813eefff8254f71b5/coverage-7.13.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f398ba4df52d30b1763f62eed9de5620dcde96e6f491f4c62686736b155aa6e4", size = 254218, upload-time = "2025-12-28T15:42:12.208Z" }, + { url = "https://files.pythonhosted.org/packages/44/ea/52a985bb447c871cb4d2e376e401116520991b597c85afdde1ea9ef54f2c/coverage-7.13.1-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:132718176cc723026d201e347f800cd1a9e4b62ccd3f82476950834dad501c75", size = 250391, upload-time = "2025-12-28T15:42:14.21Z" }, + { url = "https://files.pythonhosted.org/packages/7f/1d/125b36cc12310718873cfc8209ecfbc1008f14f4f5fa0662aa608e579353/coverage-7.13.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:9e549d642426e3579b3f4b92d0431543b012dcb6e825c91619d4e93b7363c3f9", size = 252239, upload-time = "2025-12-28T15:42:16.292Z" }, + { url = "https://files.pythonhosted.org/packages/6a/16/10c1c164950cade470107f9f14bbac8485f8fb8515f515fca53d337e4a7f/coverage-7.13.1-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:90480b2134999301eea795b3a9dbf606c6fbab1b489150c501da84a959442465", size = 250196, upload-time = "2025-12-28T15:42:18.54Z" }, + { url = "https://files.pythonhosted.org/packages/2a/c6/cd860fac08780c6fd659732f6ced1b40b79c35977c1356344e44d72ba6c4/coverage-7.13.1-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:e825dbb7f84dfa24663dd75835e7257f8882629fc11f03ecf77d84a75134b864", size = 250008, upload-time = "2025-12-28T15:42:20.365Z" }, + { url = "https://files.pythonhosted.org/packages/f0/3a/a8c58d3d38f82a5711e1e0a67268362af48e1a03df27c03072ac30feefcf/coverage-7.13.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:623dcc6d7a7ba450bbdbeedbaa0c42b329bdae16491af2282f12a7e809be7eb9", size = 251671, upload-time = "2025-12-28T15:42:22.114Z" }, + { url = "https://files.pythonhosted.org/packages/f0/bc/fd4c1da651d037a1e3d53e8cb3f8182f4b53271ffa9a95a2e211bacc0349/coverage-7.13.1-cp314-cp314-win32.whl", hash = "sha256:6e73ebb44dca5f708dc871fe0b90cf4cff1a13f9956f747cc87b535a840386f5", size = 221777, upload-time = "2025-12-28T15:42:23.919Z" }, + { url = "https://files.pythonhosted.org/packages/4b/50/71acabdc8948464c17e90b5ffd92358579bd0910732c2a1c9537d7536aa6/coverage-7.13.1-cp314-cp314-win_amd64.whl", hash = "sha256:be753b225d159feb397bd0bf91ae86f689bad0da09d3b301478cd39b878ab31a", size = 222592, upload-time = "2025-12-28T15:42:25.619Z" }, + { url = "https://files.pythonhosted.org/packages/f7/c8/a6fb943081bb0cc926499c7907731a6dc9efc2cbdc76d738c0ab752f1a32/coverage-7.13.1-cp314-cp314-win_arm64.whl", hash = "sha256:228b90f613b25ba0019361e4ab81520b343b622fc657daf7e501c4ed6a2366c0", size = 221169, upload-time = "2025-12-28T15:42:27.629Z" }, + { url = "https://files.pythonhosted.org/packages/16/61/d5b7a0a0e0e40d62e59bc8c7aa1afbd86280d82728ba97f0673b746b78e2/coverage-7.13.1-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:60cfb538fe9ef86e5b2ab0ca8fc8d62524777f6c611dcaf76dc16fbe9b8e698a", size = 219730, upload-time = "2025-12-28T15:42:29.306Z" }, + { url = "https://files.pythonhosted.org/packages/a3/2c/8881326445fd071bb49514d1ce97d18a46a980712b51fee84f9ab42845b4/coverage-7.13.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:57dfc8048c72ba48a8c45e188d811e5efd7e49b387effc8fb17e97936dde5bf6", size = 220001, upload-time = "2025-12-28T15:42:31.319Z" }, + { url = "https://files.pythonhosted.org/packages/b5/d7/50de63af51dfa3a7f91cc37ad8fcc1e244b734232fbc8b9ab0f3c834a5cd/coverage-7.13.1-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:3f2f725aa3e909b3c5fdb8192490bdd8e1495e85906af74fe6e34a2a77ba0673", size = 261370, upload-time = "2025-12-28T15:42:32.992Z" }, + { url = "https://files.pythonhosted.org/packages/e1/2c/d31722f0ec918fd7453b2758312729f645978d212b410cd0f7c2aed88a94/coverage-7.13.1-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:9ee68b21909686eeb21dfcba2c3b81fee70dcf38b140dcd5aa70680995fa3aa5", size = 263485, upload-time = "2025-12-28T15:42:34.759Z" }, + { url = "https://files.pythonhosted.org/packages/fa/7a/2c114fa5c5fc08ba0777e4aec4c97e0b4a1afcb69c75f1f54cff78b073ab/coverage-7.13.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:724b1b270cb13ea2e6503476e34541a0b1f62280bc997eab443f87790202033d", size = 265890, upload-time = "2025-12-28T15:42:36.517Z" }, + { url = "https://files.pythonhosted.org/packages/65/d9/f0794aa1c74ceabc780fe17f6c338456bbc4e96bd950f2e969f48ac6fb20/coverage-7.13.1-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:916abf1ac5cf7eb16bc540a5bf75c71c43a676f5c52fcb9fe75a2bd75fb944e8", size = 260445, upload-time = "2025-12-28T15:42:38.646Z" }, + { url = "https://files.pythonhosted.org/packages/49/23/184b22a00d9bb97488863ced9454068c79e413cb23f472da6cbddc6cfc52/coverage-7.13.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:776483fd35b58d8afe3acbd9988d5de592ab6da2d2a865edfdbc9fdb43e7c486", size = 263357, upload-time = "2025-12-28T15:42:40.788Z" }, + { url = "https://files.pythonhosted.org/packages/7d/bd/58af54c0c9199ea4190284f389005779d7daf7bf3ce40dcd2d2b2f96da69/coverage-7.13.1-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:b6f3b96617e9852703f5b633ea01315ca45c77e879584f283c44127f0f1ec564", size = 260959, upload-time = "2025-12-28T15:42:42.808Z" }, + { url = "https://files.pythonhosted.org/packages/4b/2a/6839294e8f78a4891bf1df79d69c536880ba2f970d0ff09e7513d6e352e9/coverage-7.13.1-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:bd63e7b74661fed317212fab774e2a648bc4bb09b35f25474f8e3325d2945cd7", size = 259792, upload-time = "2025-12-28T15:42:44.818Z" }, + { url = "https://files.pythonhosted.org/packages/ba/c3/528674d4623283310ad676c5af7414b9850ab6d55c2300e8aa4b945ec554/coverage-7.13.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:933082f161bbb3e9f90d00990dc956120f608cdbcaeea15c4d897f56ef4fe416", size = 262123, upload-time = "2025-12-28T15:42:47.108Z" }, + { url = "https://files.pythonhosted.org/packages/06/c5/8c0515692fb4c73ac379d8dc09b18eaf0214ecb76ea6e62467ba7a1556ff/coverage-7.13.1-cp314-cp314t-win32.whl", hash = "sha256:18be793c4c87de2965e1c0f060f03d9e5aff66cfeae8e1dbe6e5b88056ec153f", size = 222562, upload-time = "2025-12-28T15:42:49.144Z" }, + { url = "https://files.pythonhosted.org/packages/05/0e/c0a0c4678cb30dac735811db529b321d7e1c9120b79bd728d4f4d6b010e9/coverage-7.13.1-cp314-cp314t-win_amd64.whl", hash = "sha256:0e42e0ec0cd3e0d851cb3c91f770c9301f48647cb2877cb78f74bdaa07639a79", size = 223670, upload-time = "2025-12-28T15:42:51.218Z" }, + { url = "https://files.pythonhosted.org/packages/f5/5f/b177aa0011f354abf03a8f30a85032686d290fdeed4222b27d36b4372a50/coverage-7.13.1-cp314-cp314t-win_arm64.whl", hash = "sha256:eaecf47ef10c72ece9a2a92118257da87e460e113b83cc0d2905cbbe931792b4", size = 221707, upload-time = "2025-12-28T15:42:53.034Z" }, + { url = "https://files.pythonhosted.org/packages/cc/48/d9f421cb8da5afaa1a64570d9989e00fb7955e6acddc5a12979f7666ef60/coverage-7.13.1-py3-none-any.whl", hash = "sha256:2016745cb3ba554469d02819d78958b571792bb68e31302610e898f80dd3a573", size = 210722, upload-time = "2025-12-28T15:42:54.901Z" }, +] + +[[package]] +name = "cucumber-expressions" +version = "18.0.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/c6/7d/f4e231167b23b3d7348aa1c90117ce8854fae186d6984ad66d705df24061/cucumber_expressions-18.0.1.tar.gz", hash = "sha256:86ce41bf28ee520408416f38022e5a083d815edf04a0bd1dae46d474ca597c60", size = 22232, upload-time = "2024-10-28T11:38:48.672Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/80/e0/31ce90dad5234c3d52432bfce7562aa11cda4848aea90936a4be6c67d7ab/cucumber_expressions-18.0.1-py3-none-any.whl", hash = "sha256:86230d503cdda7ef35a1f2072a882d7d57c740aa4c163c82b07f039b6bc60c42", size = 20211, upload-time = "2024-10-28T11:38:47.101Z" }, +] + +[[package]] +name = "cucumber-tag-expressions" +version = "8.1.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/5c/34/968703852ad9b8351968212d63d6b7d054951eba678c9792aadfa560f447/cucumber_tag_expressions-8.1.0.tar.gz", hash = "sha256:acc56dd19b7bd0b931fc7b124ebbb6737def0775be41186ace7f5e566338ce7d", size = 8429, upload-time = "2025-11-26T13:22:04.904Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7d/b5/e85d70fd73e598499d62aa8f358591c2014b4d6c3f78f3874f0b777f31fd/cucumber_tag_expressions-8.1.0-py3-none-any.whl", hash = "sha256:1de26f183b1e8748e881189edd4bcdf4a80d7ed1011ad7b38cf141fcdcc51094", size = 9728, upload-time = "2025-11-26T13:22:05.678Z" }, +] + +[[package]] +name = "distlib" +version = "0.4.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/96/8e/709914eb2b5749865801041647dc7f4e6d00b549cfe88b65ca192995f07c/distlib-0.4.0.tar.gz", hash = "sha256:feec40075be03a04501a973d81f633735b4b69f98b05450592310c0f401a4e0d", size = 614605, upload-time = "2025-07-17T16:52:00.465Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/33/6b/e0547afaf41bf2c42e52430072fa5658766e3d65bd4b03a563d1b6336f57/distlib-0.4.0-py2.py3-none-any.whl", hash = "sha256:9659f7d87e46584a30b5780e43ac7a2143098441670ff0a49d5f9034c54a6c16", size = 469047, upload-time = "2025-07-17T16:51:58.613Z" }, +] + +[[package]] +name = "filelock" +version = "3.20.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/1d/65/ce7f1b70157833bf3cb851b556a37d4547ceafc158aa9b34b36782f23696/filelock-3.20.3.tar.gz", hash = "sha256:18c57ee915c7ec61cff0ecf7f0f869936c7c30191bb0cf406f1341778d0834e1", size = 19485, upload-time = "2026-01-09T17:55:05.421Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b5/36/7fb70f04bf00bc646cd5bb45aa9eddb15e19437a28b8fb2b4a5249fac770/filelock-3.20.3-py3-none-any.whl", hash = "sha256:4b0dda527ee31078689fc205ec4f1c1bf7d56cf88b6dc9426c4f230e46c2dce1", size = 16701, upload-time = "2026-01-09T17:55:04.334Z" }, +] + +[[package]] +name = "identify" +version = "2.6.16" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/5b/8d/e8b97e6bd3fb6fb271346f7981362f1e04d6a7463abd0de79e1fda17c067/identify-2.6.16.tar.gz", hash = "sha256:846857203b5511bbe94d5a352a48ef2359532bc8f6727b5544077a0dcfb24980", size = 99360, upload-time = "2026-01-12T18:58:58.201Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b8/58/40fbbcefeda82364720eba5cf2270f98496bdfa19ea75b4cccae79c698e6/identify-2.6.16-py2.py3-none-any.whl", hash = "sha256:391ee4d77741d994189522896270b787aed8670389bfd60f326d677d64a6dfb0", size = 99202, upload-time = "2026-01-12T18:58:56.627Z" }, +] + +[[package]] +name = "iniconfig" +version = "2.3.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/72/34/14ca021ce8e5dfedc35312d08ba8bf51fdd999c576889fc2c24cb97f4f10/iniconfig-2.3.0.tar.gz", hash = "sha256:c76315c77db068650d49c5b56314774a7804df16fee4402c1f19d6d15d8c4730", size = 20503, upload-time = "2025-10-18T21:55:43.219Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl", hash = "sha256:f631c04d2c48c52b84d0d0549c99ff3859c98df65b3101406327ecc7d53fbf12", size = 7484, upload-time = "2025-10-18T21:55:41.639Z" }, +] + +[[package]] +name = "librt" +version = "0.7.8" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e7/24/5f3646ff414285e0f7708fa4e946b9bf538345a41d1c375c439467721a5e/librt-0.7.8.tar.gz", hash = "sha256:1a4ede613941d9c3470b0368be851df6bb78ab218635512d0370b27a277a0862", size = 148323, upload-time = "2026-01-14T12:56:16.876Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1a/73/fa8814c6ce2d49c3827829cadaa1589b0bf4391660bd4510899393a23ebc/librt-0.7.8-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:be927c3c94c74b05128089a955fba86501c3b544d1d300282cc1b4bd370cb418", size = 57049, upload-time = "2026-01-14T12:55:35.056Z" }, + { url = "https://files.pythonhosted.org/packages/53/fe/f6c70956da23ea235fd2e3cc16f4f0b4ebdfd72252b02d1164dd58b4e6c3/librt-0.7.8-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:7b0803e9008c62a7ef79058233db7ff6f37a9933b8f2573c05b07ddafa226611", size = 58689, upload-time = "2026-01-14T12:55:36.078Z" }, + { url = "https://files.pythonhosted.org/packages/1f/4d/7a2481444ac5fba63050d9abe823e6bc16896f575bfc9c1e5068d516cdce/librt-0.7.8-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:79feb4d00b2a4e0e05c9c56df707934f41fcb5fe53fd9efb7549068d0495b758", size = 166808, upload-time = "2026-01-14T12:55:37.595Z" }, + { url = "https://files.pythonhosted.org/packages/ac/3c/10901d9e18639f8953f57c8986796cfbf4c1c514844a41c9197cf87cb707/librt-0.7.8-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b9122094e3f24aa759c38f46bd8863433820654927370250f460ae75488b66ea", size = 175614, upload-time = "2026-01-14T12:55:38.756Z" }, + { url = "https://files.pythonhosted.org/packages/db/01/5cbdde0951a5090a80e5ba44e6357d375048123c572a23eecfb9326993a7/librt-0.7.8-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7e03bea66af33c95ce3addf87a9bf1fcad8d33e757bc479957ddbc0e4f7207ac", size = 189955, upload-time = "2026-01-14T12:55:39.939Z" }, + { url = "https://files.pythonhosted.org/packages/6a/b4/e80528d2f4b7eaf1d437fcbd6fc6ba4cbeb3e2a0cb9ed5a79f47c7318706/librt-0.7.8-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:f1ade7f31675db00b514b98f9ab9a7698c7282dad4be7492589109471852d398", size = 189370, upload-time = "2026-01-14T12:55:41.057Z" }, + { url = "https://files.pythonhosted.org/packages/c1/ab/938368f8ce31a9787ecd4becb1e795954782e4312095daf8fd22420227c8/librt-0.7.8-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:a14229ac62adcf1b90a15992f1ab9c69ae8b99ffb23cb64a90878a6e8a2f5b81", size = 183224, upload-time = "2026-01-14T12:55:42.328Z" }, + { url = "https://files.pythonhosted.org/packages/3c/10/559c310e7a6e4014ac44867d359ef8238465fb499e7eb31b6bfe3e3f86f5/librt-0.7.8-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:5bcaaf624fd24e6a0cb14beac37677f90793a96864c67c064a91458611446e83", size = 203541, upload-time = "2026-01-14T12:55:43.501Z" }, + { url = "https://files.pythonhosted.org/packages/f8/db/a0db7acdb6290c215f343835c6efda5b491bb05c3ddc675af558f50fdba3/librt-0.7.8-cp314-cp314-win32.whl", hash = "sha256:7aa7d5457b6c542ecaed79cec4ad98534373c9757383973e638ccced0f11f46d", size = 40657, upload-time = "2026-01-14T12:55:44.668Z" }, + { url = "https://files.pythonhosted.org/packages/72/e0/4f9bdc2a98a798511e81edcd6b54fe82767a715e05d1921115ac70717f6f/librt-0.7.8-cp314-cp314-win_amd64.whl", hash = "sha256:3d1322800771bee4a91f3b4bd4e49abc7d35e65166821086e5afd1e6c0d9be44", size = 46835, upload-time = "2026-01-14T12:55:45.655Z" }, + { url = "https://files.pythonhosted.org/packages/f9/3d/59c6402e3dec2719655a41ad027a7371f8e2334aa794ed11533ad5f34969/librt-0.7.8-cp314-cp314-win_arm64.whl", hash = "sha256:5363427bc6a8c3b1719f8f3845ea53553d301382928a86e8fab7984426949bce", size = 39885, upload-time = "2026-01-14T12:55:47.138Z" }, + { url = "https://files.pythonhosted.org/packages/4e/9c/2481d80950b83085fb14ba3c595db56330d21bbc7d88a19f20165f3538db/librt-0.7.8-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:ca916919793a77e4a98d4a1701e345d337ce53be4a16620f063191f7322ac80f", size = 59161, upload-time = "2026-01-14T12:55:48.45Z" }, + { url = "https://files.pythonhosted.org/packages/96/79/108df2cfc4e672336765d54e3ff887294c1cc36ea4335c73588875775527/librt-0.7.8-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:54feb7b4f2f6706bb82325e836a01be805770443e2400f706e824e91f6441dde", size = 61008, upload-time = "2026-01-14T12:55:49.527Z" }, + { url = "https://files.pythonhosted.org/packages/46/f2/30179898f9994a5637459d6e169b6abdc982012c0a4b2d4c26f50c06f911/librt-0.7.8-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:39a4c76fee41007070f872b648cc2f711f9abf9a13d0c7162478043377b52c8e", size = 187199, upload-time = "2026-01-14T12:55:50.587Z" }, + { url = "https://files.pythonhosted.org/packages/b4/da/f7563db55cebdc884f518ba3791ad033becc25ff68eb70902b1747dc0d70/librt-0.7.8-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ac9c8a458245c7de80bc1b9765b177055efff5803f08e548dd4bb9ab9a8d789b", size = 198317, upload-time = "2026-01-14T12:55:51.991Z" }, + { url = "https://files.pythonhosted.org/packages/b3/6c/4289acf076ad371471fa86718c30ae353e690d3de6167f7db36f429272f1/librt-0.7.8-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:95b67aa7eff150f075fda09d11f6bfb26edffd300f6ab1666759547581e8f666", size = 210334, upload-time = "2026-01-14T12:55:53.682Z" }, + { url = "https://files.pythonhosted.org/packages/4a/7f/377521ac25b78ac0a5ff44127a0360ee6d5ddd3ce7327949876a30533daa/librt-0.7.8-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:535929b6eff670c593c34ff435d5440c3096f20fa72d63444608a5aef64dd581", size = 211031, upload-time = "2026-01-14T12:55:54.827Z" }, + { url = "https://files.pythonhosted.org/packages/c5/b1/e1e96c3e20b23d00cf90f4aad48f0deb4cdfec2f0ed8380d0d85acf98bbf/librt-0.7.8-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:63937bd0f4d1cb56653dc7ae900d6c52c41f0015e25aaf9902481ee79943b33a", size = 204581, upload-time = "2026-01-14T12:55:56.811Z" }, + { url = "https://files.pythonhosted.org/packages/43/71/0f5d010e92ed9747e14bef35e91b6580533510f1e36a8a09eb79ee70b2f0/librt-0.7.8-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:cf243da9e42d914036fd362ac3fa77d80a41cadcd11ad789b1b5eec4daaf67ca", size = 224731, upload-time = "2026-01-14T12:55:58.175Z" }, + { url = "https://files.pythonhosted.org/packages/22/f0/07fb6ab5c39a4ca9af3e37554f9d42f25c464829254d72e4ebbd81da351c/librt-0.7.8-cp314-cp314t-win32.whl", hash = "sha256:171ca3a0a06c643bd0a2f62a8944e1902c94aa8e5da4db1ea9a8daf872685365", size = 41173, upload-time = "2026-01-14T12:55:59.315Z" }, + { url = "https://files.pythonhosted.org/packages/24/d4/7e4be20993dc6a782639625bd2f97f3c66125c7aa80c82426956811cfccf/librt-0.7.8-cp314-cp314t-win_amd64.whl", hash = "sha256:445b7304145e24c60288a2f172b5ce2ca35c0f81605f5299f3fa567e189d2e32", size = 47668, upload-time = "2026-01-14T12:56:00.261Z" }, + { url = "https://files.pythonhosted.org/packages/fc/85/69f92b2a7b3c0f88ffe107c86b952b397004b5b8ea5a81da3d9c04c04422/librt-0.7.8-cp314-cp314t-win_arm64.whl", hash = "sha256:8766ece9de08527deabcd7cb1b4f1a967a385d26e33e536d6d8913db6ef74f06", size = 40550, upload-time = "2026-01-14T12:56:01.542Z" }, +] + +[[package]] +name = "morphir" +version = "0.1.0" +source = { editable = "packages/morphir" } + +[[package]] +name = "morphir-tools" +version = "0.1.0" +source = { editable = "packages/morphir-tools" } +dependencies = [ + { name = "morphir" }, +] + +[package.metadata] +requires-dist = [{ name = "morphir", editable = "packages/morphir" }] + +[[package]] +name = "morphir-workspace" +version = "0.1.0" +source = { virtual = "." } + +[package.dev-dependencies] +dev = [ + { name = "mypy" }, + { name = "pre-commit" }, + { name = "pyright" }, + { name = "ruff" }, +] +test = [ + { name = "behave" }, + { name = "coverage" }, + { name = "pytest" }, + { name = "pytest-cov" }, +] + +[package.metadata] + +[package.metadata.requires-dev] +dev = [ + { name = "mypy", specifier = ">=1.13" }, + { name = "pre-commit", specifier = ">=4.0" }, + { name = "pyright", specifier = ">=1.1" }, + { name = "ruff", specifier = ">=0.8" }, +] +test = [ + { name = "behave", specifier = ">=1.2" }, + { name = "coverage", specifier = ">=7.0" }, + { name = "pytest", specifier = ">=8.0" }, + { name = "pytest-cov", specifier = ">=6.0" }, +] + +[[package]] +name = "mypy" +version = "1.19.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "librt", marker = "platform_python_implementation != 'PyPy'" }, + { name = "mypy-extensions" }, + { name = "pathspec" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/f5/db/4efed9504bc01309ab9c2da7e352cc223569f05478012b5d9ece38fd44d2/mypy-1.19.1.tar.gz", hash = "sha256:19d88bb05303fe63f71dd2c6270daca27cb9401c4ca8255fe50d1d920e0eb9ba", size = 3582404, upload-time = "2025-12-15T05:03:48.42Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/de/eb/b83e75f4c820c4247a58580ef86fcd35165028f191e7e1ba57128c52782d/mypy-1.19.1-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:06e6170bd5836770e8104c8fdd58e5e725cfeb309f0a6c681a811f557e97eac1", size = 13199744, upload-time = "2025-12-15T05:03:30.823Z" }, + { url = "https://files.pythonhosted.org/packages/94/28/52785ab7bfa165f87fcbb61547a93f98bb20e7f82f90f165a1f69bce7b3d/mypy-1.19.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:804bd67b8054a85447c8954215a906d6eff9cabeabe493fb6334b24f4bfff718", size = 12215815, upload-time = "2025-12-15T05:02:42.323Z" }, + { url = "https://files.pythonhosted.org/packages/0a/c6/bdd60774a0dbfb05122e3e925f2e9e846c009e479dcec4821dad881f5b52/mypy-1.19.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:21761006a7f497cb0d4de3d8ef4ca70532256688b0523eee02baf9eec895e27b", size = 12740047, upload-time = "2025-12-15T05:03:33.168Z" }, + { url = "https://files.pythonhosted.org/packages/32/2a/66ba933fe6c76bd40d1fe916a83f04fed253152f451a877520b3c4a5e41e/mypy-1.19.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:28902ee51f12e0f19e1e16fbe2f8f06b6637f482c459dd393efddd0ec7f82045", size = 13601998, upload-time = "2025-12-15T05:03:13.056Z" }, + { url = "https://files.pythonhosted.org/packages/e3/da/5055c63e377c5c2418760411fd6a63ee2b96cf95397259038756c042574f/mypy-1.19.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:481daf36a4c443332e2ae9c137dfee878fcea781a2e3f895d54bd3002a900957", size = 13807476, upload-time = "2025-12-15T05:03:17.977Z" }, + { url = "https://files.pythonhosted.org/packages/cd/09/4ebd873390a063176f06b0dbf1f7783dd87bd120eae7727fa4ae4179b685/mypy-1.19.1-cp314-cp314-win_amd64.whl", hash = "sha256:8bb5c6f6d043655e055be9b542aa5f3bdd30e4f3589163e85f93f3640060509f", size = 10281872, upload-time = "2025-12-15T05:03:05.549Z" }, + { url = "https://files.pythonhosted.org/packages/8d/f4/4ce9a05ce5ded1de3ec1c1d96cf9f9504a04e54ce0ed55cfa38619a32b8d/mypy-1.19.1-py3-none-any.whl", hash = "sha256:f1235f5ea01b7db5468d53ece6aaddf1ad0b88d9e7462b86ef96fe04995d7247", size = 2471239, upload-time = "2025-12-15T05:03:07.248Z" }, +] + +[[package]] +name = "mypy-extensions" +version = "1.1.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a2/6e/371856a3fb9d31ca8dac321cda606860fa4548858c0cc45d9d1d4ca2628b/mypy_extensions-1.1.0.tar.gz", hash = "sha256:52e68efc3284861e772bbcd66823fde5ae21fd2fdb51c62a211403730b916558", size = 6343, upload-time = "2025-04-22T14:54:24.164Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/79/7b/2c79738432f5c924bef5071f933bcc9efd0473bac3b4aa584a6f7c1c8df8/mypy_extensions-1.1.0-py3-none-any.whl", hash = "sha256:1be4cccdb0f2482337c4743e60421de3a356cd97508abadd57d47403e94f5505", size = 4963, upload-time = "2025-04-22T14:54:22.983Z" }, +] + +[[package]] +name = "nodeenv" +version = "1.10.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/24/bf/d1bda4f6168e0b2e9e5958945e01910052158313224ada5ce1fb2e1113b8/nodeenv-1.10.0.tar.gz", hash = "sha256:996c191ad80897d076bdfba80a41994c2b47c68e224c542b48feba42ba00f8bb", size = 55611, upload-time = "2025-12-20T14:08:54.006Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/88/b2/d0896bdcdc8d28a7fc5717c305f1a861c26e18c05047949fb371034d98bd/nodeenv-1.10.0-py2.py3-none-any.whl", hash = "sha256:5bb13e3eed2923615535339b3c620e76779af4cb4c6a90deccc9e36b274d3827", size = 23438, upload-time = "2025-12-20T14:08:52.782Z" }, +] + +[[package]] +name = "packaging" +version = "25.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a1/d4/1fc4078c65507b51b96ca8f8c3ba19e6a61c8253c72794544580a7b6c24d/packaging-25.0.tar.gz", hash = "sha256:d443872c98d677bf60f6a1f2f8c1cb748e8fe762d2bf9d3148b5599295b0fc4f", size = 165727, upload-time = "2025-04-19T11:48:59.673Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/20/12/38679034af332785aac8774540895e234f4d07f7545804097de4b666afd8/packaging-25.0-py3-none-any.whl", hash = "sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484", size = 66469, upload-time = "2025-04-19T11:48:57.875Z" }, +] + +[[package]] +name = "parse" +version = "1.20.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/4f/78/d9b09ba24bb36ef8b83b71be547e118d46214735b6dfb39e4bfde0e9b9dd/parse-1.20.2.tar.gz", hash = "sha256:b41d604d16503c79d81af5165155c0b20f6c8d6c559efa66b4b695c3e5a0a0ce", size = 29391, upload-time = "2024-06-11T04:41:57.34Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d0/31/ba45bf0b2aa7898d81cbbfac0e88c267befb59ad91a19e36e1bc5578ddb1/parse-1.20.2-py2.py3-none-any.whl", hash = "sha256:967095588cb802add9177d0c0b6133b5ba33b1ea9007ca800e526f42a85af558", size = 20126, upload-time = "2024-06-11T04:41:55.057Z" }, +] + +[[package]] +name = "parse-type" +version = "0.6.6" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "parse" }, + { name = "six" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/19/ea/42ba6ce0abba04ab6e0b997dcb9b528a4661b62af1fe1b0d498120d5ea78/parse_type-0.6.6.tar.gz", hash = "sha256:513a3784104839770d690e04339a8b4d33439fcd5dd99f2e4580f9fc1097bfb2", size = 98012, upload-time = "2025-08-11T22:53:48.066Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/85/8d/eef3d8cdccc32abdd91b1286884c99b8c3a6d3b135affcc2a7a0f383bb32/parse_type-0.6.6-py2.py3-none-any.whl", hash = "sha256:3ca79bbe71e170dfccc8ec6c341edfd1c2a0fc1e5cfd18330f93af938de2348c", size = 27085, upload-time = "2025-08-11T22:53:46.396Z" }, +] + +[[package]] +name = "pathspec" +version = "1.0.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/4c/b2/bb8e495d5262bfec41ab5cb18f522f1012933347fb5d9e62452d446baca2/pathspec-1.0.3.tar.gz", hash = "sha256:bac5cf97ae2c2876e2d25ebb15078eb04d76e4b98921ee31c6f85ade8b59444d", size = 130841, upload-time = "2026-01-09T15:46:46.009Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/32/2b/121e912bd60eebd623f873fd090de0e84f322972ab25a7f9044c056804ed/pathspec-1.0.3-py3-none-any.whl", hash = "sha256:e80767021c1cc524aa3fb14bedda9c34406591343cc42797b386ce7b9354fb6c", size = 55021, upload-time = "2026-01-09T15:46:44.652Z" }, +] + +[[package]] +name = "platformdirs" +version = "4.5.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/cf/86/0248f086a84f01b37aaec0fa567b397df1a119f73c16f6c7a9aac73ea309/platformdirs-4.5.1.tar.gz", hash = "sha256:61d5cdcc6065745cdd94f0f878977f8de9437be93de97c1c12f853c9c0cdcbda", size = 21715, upload-time = "2025-12-05T13:52:58.638Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/cb/28/3bfe2fa5a7b9c46fe7e13c97bda14c895fb10fa2ebf1d0abb90e0cea7ee1/platformdirs-4.5.1-py3-none-any.whl", hash = "sha256:d03afa3963c806a9bed9d5125c8f4cb2fdaf74a55ab60e5d59b3fde758104d31", size = 18731, upload-time = "2025-12-05T13:52:56.823Z" }, +] + +[[package]] +name = "pluggy" +version = "1.6.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f9/e2/3e91f31a7d2b083fe6ef3fa267035b518369d9511ffab804f839851d2779/pluggy-1.6.0.tar.gz", hash = "sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3", size = 69412, upload-time = "2025-05-15T12:30:07.975Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746", size = 20538, upload-time = "2025-05-15T12:30:06.134Z" }, +] + +[[package]] +name = "pre-commit" +version = "4.5.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cfgv" }, + { name = "identify" }, + { name = "nodeenv" }, + { name = "pyyaml" }, + { name = "virtualenv" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/40/f1/6d86a29246dfd2e9b6237f0b5823717f60cad94d47ddc26afa916d21f525/pre_commit-4.5.1.tar.gz", hash = "sha256:eb545fcff725875197837263e977ea257a402056661f09dae08e4b149b030a61", size = 198232, upload-time = "2025-12-16T21:14:33.552Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5d/19/fd3ef348460c80af7bb4669ea7926651d1f95c23ff2df18b9d24bab4f3fa/pre_commit-4.5.1-py2.py3-none-any.whl", hash = "sha256:3b3afd891e97337708c1674210f8eba659b52a38ea5f822ff142d10786221f77", size = 226437, upload-time = "2025-12-16T21:14:32.409Z" }, +] + +[[package]] +name = "pygments" +version = "2.19.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/b0/77/a5b8c569bf593b0140bde72ea885a803b82086995367bf2037de0159d924/pygments-2.19.2.tar.gz", hash = "sha256:636cb2477cec7f8952536970bc533bc43743542f70392ae026374600add5b887", size = 4968631, upload-time = "2025-06-21T13:39:12.283Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c7/21/705964c7812476f378728bdf590ca4b771ec72385c533964653c68e86bdc/pygments-2.19.2-py3-none-any.whl", hash = "sha256:86540386c03d588bb81d44bc3928634ff26449851e99741617ecb9037ee5ec0b", size = 1225217, upload-time = "2025-06-21T13:39:07.939Z" }, +] + +[[package]] +name = "pyright" +version = "1.1.408" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "nodeenv" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/74/b2/5db700e52554b8f025faa9c3c624c59f1f6c8841ba81ab97641b54322f16/pyright-1.1.408.tar.gz", hash = "sha256:f28f2321f96852fa50b5829ea492f6adb0e6954568d1caa3f3af3a5f555eb684", size = 4400578, upload-time = "2026-01-08T08:07:38.795Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0c/82/a2c93e32800940d9573fb28c346772a14778b84ba7524e691b324620ab89/pyright-1.1.408-py3-none-any.whl", hash = "sha256:090b32865f4fdb1e0e6cd82bf5618480d48eecd2eb2e70f960982a3d9a4c17c1", size = 6399144, upload-time = "2026-01-08T08:07:37.082Z" }, +] + +[[package]] +name = "pytest" +version = "9.0.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, + { name = "iniconfig" }, + { name = "packaging" }, + { name = "pluggy" }, + { name = "pygments" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/d1/db/7ef3487e0fb0049ddb5ce41d3a49c235bf9ad299b6a25d5780a89f19230f/pytest-9.0.2.tar.gz", hash = "sha256:75186651a92bd89611d1d9fc20f0b4345fd827c41ccd5c299a868a05d70edf11", size = 1568901, upload-time = "2025-12-06T21:30:51.014Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3b/ab/b3226f0bd7cdcf710fbede2b3548584366da3b19b5021e74f5bde2a8fa3f/pytest-9.0.2-py3-none-any.whl", hash = "sha256:711ffd45bf766d5264d487b917733b453d917afd2b0ad65223959f59089f875b", size = 374801, upload-time = "2025-12-06T21:30:49.154Z" }, +] + +[[package]] +name = "pytest-cov" +version = "7.0.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "coverage" }, + { name = "pluggy" }, + { name = "pytest" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/5e/f7/c933acc76f5208b3b00089573cf6a2bc26dc80a8aece8f52bb7d6b1855ca/pytest_cov-7.0.0.tar.gz", hash = "sha256:33c97eda2e049a0c5298e91f519302a1334c26ac65c1a483d6206fd458361af1", size = 54328, upload-time = "2025-09-09T10:57:02.113Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ee/49/1377b49de7d0c1ce41292161ea0f721913fa8722c19fb9c1e3aa0367eecb/pytest_cov-7.0.0-py3-none-any.whl", hash = "sha256:3b8e9558b16cc1479da72058bdecf8073661c7f57f7d3c5f22a1c23507f2d861", size = 22424, upload-time = "2025-09-09T10:57:00.695Z" }, +] + +[[package]] +name = "pyyaml" +version = "6.0.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/05/8e/961c0007c59b8dd7729d542c61a4d537767a59645b82a0b521206e1e25c2/pyyaml-6.0.3.tar.gz", hash = "sha256:d76623373421df22fb4cf8817020cbb7ef15c725b9d5e45f17e189bfc384190f", size = 130960, upload-time = "2025-09-25T21:33:16.546Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9d/8c/f4bd7f6465179953d3ac9bc44ac1a8a3e6122cf8ada906b4f96c60172d43/pyyaml-6.0.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:8d1fab6bb153a416f9aeb4b8763bc0f22a5586065f86f7664fc23339fc1c1fac", size = 181814, upload-time = "2025-09-25T21:32:35.712Z" }, + { url = "https://files.pythonhosted.org/packages/bd/9c/4d95bb87eb2063d20db7b60faa3840c1b18025517ae857371c4dd55a6b3a/pyyaml-6.0.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:34d5fcd24b8445fadc33f9cf348c1047101756fd760b4dacb5c3e99755703310", size = 173809, upload-time = "2025-09-25T21:32:36.789Z" }, + { url = "https://files.pythonhosted.org/packages/92/b5/47e807c2623074914e29dabd16cbbdd4bf5e9b2db9f8090fa64411fc5382/pyyaml-6.0.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:501a031947e3a9025ed4405a168e6ef5ae3126c59f90ce0cd6f2bfc477be31b7", size = 766454, upload-time = "2025-09-25T21:32:37.966Z" }, + { url = "https://files.pythonhosted.org/packages/02/9e/e5e9b168be58564121efb3de6859c452fccde0ab093d8438905899a3a483/pyyaml-6.0.3-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:b3bc83488de33889877a0f2543ade9f70c67d66d9ebb4ac959502e12de895788", size = 836355, upload-time = "2025-09-25T21:32:39.178Z" }, + { url = "https://files.pythonhosted.org/packages/88/f9/16491d7ed2a919954993e48aa941b200f38040928474c9e85ea9e64222c3/pyyaml-6.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c458b6d084f9b935061bc36216e8a69a7e293a2f1e68bf956dcd9e6cbcd143f5", size = 794175, upload-time = "2025-09-25T21:32:40.865Z" }, + { url = "https://files.pythonhosted.org/packages/dd/3f/5989debef34dc6397317802b527dbbafb2b4760878a53d4166579111411e/pyyaml-6.0.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:7c6610def4f163542a622a73fb39f534f8c101d690126992300bf3207eab9764", size = 755228, upload-time = "2025-09-25T21:32:42.084Z" }, + { url = "https://files.pythonhosted.org/packages/d7/ce/af88a49043cd2e265be63d083fc75b27b6ed062f5f9fd6cdc223ad62f03e/pyyaml-6.0.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:5190d403f121660ce8d1d2c1bb2ef1bd05b5f68533fc5c2ea899bd15f4399b35", size = 789194, upload-time = "2025-09-25T21:32:43.362Z" }, + { url = "https://files.pythonhosted.org/packages/23/20/bb6982b26a40bb43951265ba29d4c246ef0ff59c9fdcdf0ed04e0687de4d/pyyaml-6.0.3-cp314-cp314-win_amd64.whl", hash = "sha256:4a2e8cebe2ff6ab7d1050ecd59c25d4c8bd7e6f400f5f82b96557ac0abafd0ac", size = 156429, upload-time = "2025-09-25T21:32:57.844Z" }, + { url = "https://files.pythonhosted.org/packages/f4/f4/a4541072bb9422c8a883ab55255f918fa378ecf083f5b85e87fc2b4eda1b/pyyaml-6.0.3-cp314-cp314-win_arm64.whl", hash = "sha256:93dda82c9c22deb0a405ea4dc5f2d0cda384168e466364dec6255b293923b2f3", size = 143912, upload-time = "2025-09-25T21:32:59.247Z" }, + { url = "https://files.pythonhosted.org/packages/7c/f9/07dd09ae774e4616edf6cda684ee78f97777bdd15847253637a6f052a62f/pyyaml-6.0.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:02893d100e99e03eda1c8fd5c441d8c60103fd175728e23e431db1b589cf5ab3", size = 189108, upload-time = "2025-09-25T21:32:44.377Z" }, + { url = "https://files.pythonhosted.org/packages/4e/78/8d08c9fb7ce09ad8c38ad533c1191cf27f7ae1effe5bb9400a46d9437fcf/pyyaml-6.0.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:c1ff362665ae507275af2853520967820d9124984e0f7466736aea23d8611fba", size = 183641, upload-time = "2025-09-25T21:32:45.407Z" }, + { url = "https://files.pythonhosted.org/packages/7b/5b/3babb19104a46945cf816d047db2788bcaf8c94527a805610b0289a01c6b/pyyaml-6.0.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6adc77889b628398debc7b65c073bcb99c4a0237b248cacaf3fe8a557563ef6c", size = 831901, upload-time = "2025-09-25T21:32:48.83Z" }, + { url = "https://files.pythonhosted.org/packages/8b/cc/dff0684d8dc44da4d22a13f35f073d558c268780ce3c6ba1b87055bb0b87/pyyaml-6.0.3-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a80cb027f6b349846a3bf6d73b5e95e782175e52f22108cfa17876aaeff93702", size = 861132, upload-time = "2025-09-25T21:32:50.149Z" }, + { url = "https://files.pythonhosted.org/packages/b1/5e/f77dc6b9036943e285ba76b49e118d9ea929885becb0a29ba8a7c75e29fe/pyyaml-6.0.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:00c4bdeba853cc34e7dd471f16b4114f4162dc03e6b7afcc2128711f0eca823c", size = 839261, upload-time = "2025-09-25T21:32:51.808Z" }, + { url = "https://files.pythonhosted.org/packages/ce/88/a9db1376aa2a228197c58b37302f284b5617f56a5d959fd1763fb1675ce6/pyyaml-6.0.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:66e1674c3ef6f541c35191caae2d429b967b99e02040f5ba928632d9a7f0f065", size = 805272, upload-time = "2025-09-25T21:32:52.941Z" }, + { url = "https://files.pythonhosted.org/packages/da/92/1446574745d74df0c92e6aa4a7b0b3130706a4142b2d1a5869f2eaa423c6/pyyaml-6.0.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:16249ee61e95f858e83976573de0f5b2893b3677ba71c9dd36b9cf8be9ac6d65", size = 829923, upload-time = "2025-09-25T21:32:54.537Z" }, + { url = "https://files.pythonhosted.org/packages/f0/7a/1c7270340330e575b92f397352af856a8c06f230aa3e76f86b39d01b416a/pyyaml-6.0.3-cp314-cp314t-win_amd64.whl", hash = "sha256:4ad1906908f2f5ae4e5a8ddfce73c320c2a1429ec52eafd27138b7f1cbe341c9", size = 174062, upload-time = "2025-09-25T21:32:55.767Z" }, + { url = "https://files.pythonhosted.org/packages/f1/12/de94a39c2ef588c7e6455cfbe7343d3b2dc9d6b6b2f40c4c6565744c873d/pyyaml-6.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:ebc55a14a21cb14062aa4162f906cd962b28e2e9ea38f9b4391244cd8de4ae0b", size = 149341, upload-time = "2025-09-25T21:32:56.828Z" }, +] + +[[package]] +name = "ruff" +version = "0.14.13" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/50/0a/1914efb7903174b381ee2ffeebb4253e729de57f114e63595114c8ca451f/ruff-0.14.13.tar.gz", hash = "sha256:83cd6c0763190784b99650a20fec7633c59f6ebe41c5cc9d45ee42749563ad47", size = 6059504, upload-time = "2026-01-15T20:15:16.918Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c3/ae/0deefbc65ca74b0ab1fd3917f94dc3b398233346a74b8bbb0a916a1a6bf6/ruff-0.14.13-py3-none-linux_armv6l.whl", hash = "sha256:76f62c62cd37c276cb03a275b198c7c15bd1d60c989f944db08a8c1c2dbec18b", size = 13062418, upload-time = "2026-01-15T20:14:50.779Z" }, + { url = "https://files.pythonhosted.org/packages/47/df/5916604faa530a97a3c154c62a81cb6b735c0cb05d1e26d5ad0f0c8ac48a/ruff-0.14.13-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:914a8023ece0528d5cc33f5a684f5f38199bbb566a04815c2c211d8f40b5d0ed", size = 13442344, upload-time = "2026-01-15T20:15:07.94Z" }, + { url = "https://files.pythonhosted.org/packages/4c/f3/e0e694dd69163c3a1671e102aa574a50357536f18a33375050334d5cd517/ruff-0.14.13-py3-none-macosx_11_0_arm64.whl", hash = "sha256:d24899478c35ebfa730597a4a775d430ad0d5631b8647a3ab368c29b7e7bd063", size = 12354720, upload-time = "2026-01-15T20:15:09.854Z" }, + { url = "https://files.pythonhosted.org/packages/c3/e8/67f5fcbbaee25e8fc3b56cc33e9892eca7ffe09f773c8e5907757a7e3bdb/ruff-0.14.13-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9aaf3870f14d925bbaf18b8a2347ee0ae7d95a2e490e4d4aea6813ed15ebc80e", size = 12774493, upload-time = "2026-01-15T20:15:20.908Z" }, + { url = "https://files.pythonhosted.org/packages/6b/ce/d2e9cb510870b52a9565d885c0d7668cc050e30fa2c8ac3fb1fda15c083d/ruff-0.14.13-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ac5b7f63dd3b27cc811850f5ffd8fff845b00ad70e60b043aabf8d6ecc304e09", size = 12815174, upload-time = "2026-01-15T20:15:05.74Z" }, + { url = "https://files.pythonhosted.org/packages/88/00/c38e5da58beebcf4fa32d0ddd993b63dfacefd02ab7922614231330845bf/ruff-0.14.13-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:78d2b1097750d90ba82ce4ba676e85230a0ed694178ca5e61aa9b459970b3eb9", size = 13680909, upload-time = "2026-01-15T20:15:14.537Z" }, + { url = "https://files.pythonhosted.org/packages/61/61/cd37c9dd5bd0a3099ba79b2a5899ad417d8f3b04038810b0501a80814fd7/ruff-0.14.13-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:7d0bf87705acbbcb8d4c24b2d77fbb73d40210a95c3903b443cd9e30824a5032", size = 15144215, upload-time = "2026-01-15T20:15:22.886Z" }, + { url = "https://files.pythonhosted.org/packages/56/8a/85502d7edbf98c2df7b8876f316c0157359165e16cdf98507c65c8d07d3d/ruff-0.14.13-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a3eb5da8e2c9e9f13431032fdcbe7681de9ceda5835efee3269417c13f1fed5c", size = 14706067, upload-time = "2026-01-15T20:14:48.271Z" }, + { url = "https://files.pythonhosted.org/packages/7e/2f/de0df127feb2ee8c1e54354dc1179b4a23798f0866019528c938ba439aca/ruff-0.14.13-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:642442b42957093811cd8d2140dfadd19c7417030a7a68cf8d51fcdd5f217427", size = 14133916, upload-time = "2026-01-15T20:14:57.357Z" }, + { url = "https://files.pythonhosted.org/packages/0d/77/9b99686bb9fe07a757c82f6f95e555c7a47801a9305576a9c67e0a31d280/ruff-0.14.13-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4acdf009f32b46f6e8864af19cbf6841eaaed8638e65c8dac845aea0d703c841", size = 13859207, upload-time = "2026-01-15T20:14:55.111Z" }, + { url = "https://files.pythonhosted.org/packages/7d/46/2bdcb34a87a179a4d23022d818c1c236cb40e477faf0d7c9afb6813e5876/ruff-0.14.13-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:591a7f68860ea4e003917d19b5c4f5ac39ff558f162dc753a2c5de897fd5502c", size = 14043686, upload-time = "2026-01-15T20:14:52.841Z" }, + { url = "https://files.pythonhosted.org/packages/1a/a9/5c6a4f56a0512c691cf143371bcf60505ed0f0860f24a85da8bd123b2bf1/ruff-0.14.13-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:774c77e841cc6e046fc3e91623ce0903d1cd07e3a36b1a9fe79b81dab3de506b", size = 12663837, upload-time = "2026-01-15T20:15:18.921Z" }, + { url = "https://files.pythonhosted.org/packages/fe/bb/b920016ece7651fa7fcd335d9d199306665486694d4361547ccb19394c44/ruff-0.14.13-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:61f4e40077a1248436772bb6512db5fc4457fe4c49e7a94ea7c5088655dd21ae", size = 12805867, upload-time = "2026-01-15T20:14:59.272Z" }, + { url = "https://files.pythonhosted.org/packages/7d/b3/0bd909851e5696cd21e32a8fc25727e5f58f1934b3596975503e6e85415c/ruff-0.14.13-py3-none-musllinux_1_2_i686.whl", hash = "sha256:6d02f1428357fae9e98ac7aa94b7e966fd24151088510d32cf6f902d6c09235e", size = 13208528, upload-time = "2026-01-15T20:15:03.732Z" }, + { url = "https://files.pythonhosted.org/packages/3b/3b/e2d94cb613f6bbd5155a75cbe072813756363eba46a3f2177a1fcd0cd670/ruff-0.14.13-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:e399341472ce15237be0c0ae5fbceca4b04cd9bebab1a2b2c979e015455d8f0c", size = 13929242, upload-time = "2026-01-15T20:15:11.918Z" }, + { url = "https://files.pythonhosted.org/packages/6a/c5/abd840d4132fd51a12f594934af5eba1d5d27298a6f5b5d6c3be45301caf/ruff-0.14.13-py3-none-win32.whl", hash = "sha256:ef720f529aec113968b45dfdb838ac8934e519711da53a0456038a0efecbd680", size = 12919024, upload-time = "2026-01-15T20:14:43.647Z" }, + { url = "https://files.pythonhosted.org/packages/c2/55/6384b0b8ce731b6e2ade2b5449bf07c0e4c31e8a2e68ea65b3bafadcecc5/ruff-0.14.13-py3-none-win_amd64.whl", hash = "sha256:6070bd026e409734b9257e03e3ef18c6e1a216f0435c6751d7a8ec69cb59abef", size = 14097887, upload-time = "2026-01-15T20:15:01.48Z" }, + { url = "https://files.pythonhosted.org/packages/4d/e1/7348090988095e4e39560cfc2f7555b1b2a7357deba19167b600fdf5215d/ruff-0.14.13-py3-none-win_arm64.whl", hash = "sha256:7ab819e14f1ad9fe39f246cfcc435880ef7a9390d81a2b6ac7e01039083dd247", size = 13080224, upload-time = "2026-01-15T20:14:45.853Z" }, +] + +[[package]] +name = "six" +version = "1.17.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/94/e7/b2c673351809dca68a0e064b6af791aa332cf192da575fd474ed7d6f16a2/six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81", size = 34031, upload-time = "2024-12-04T17:35:28.174Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", size = 11050, upload-time = "2024-12-04T17:35:26.475Z" }, +] + +[[package]] +name = "typing-extensions" +version = "4.15.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/72/94/1a15dd82efb362ac84269196e94cf00f187f7ed21c242792a923cdb1c61f/typing_extensions-4.15.0.tar.gz", hash = "sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466", size = 109391, upload-time = "2025-08-25T13:49:26.313Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl", hash = "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548", size = 44614, upload-time = "2025-08-25T13:49:24.86Z" }, +] + +[[package]] +name = "virtualenv" +version = "20.36.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "distlib" }, + { name = "filelock" }, + { name = "platformdirs" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/aa/a3/4d310fa5f00863544e1d0f4de93bddec248499ccf97d4791bc3122c9d4f3/virtualenv-20.36.1.tar.gz", hash = "sha256:8befb5c81842c641f8ee658481e42641c68b5eab3521d8e092d18320902466ba", size = 6032239, upload-time = "2026-01-09T18:21:01.296Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/6a/2a/dc2228b2888f51192c7dc766106cd475f1b768c10caaf9727659726f7391/virtualenv-20.36.1-py3-none-any.whl", hash = "sha256:575a8d6b124ef88f6f51d56d656132389f961062a9177016a50e4f507bbcc19f", size = 6008258, upload-time = "2026-01-09T18:20:59.425Z" }, +] From 006ff32cc60323f00d9ea627897de772d2ed4939 Mon Sep 17 00:00:00 2001 From: Damian Reeves <957246+DamianReeves@users.noreply.github.com> Date: Mon, 19 Jan 2026 17:07:46 -0600 Subject: [PATCH 3/6] fix(ci): Use --all-groups to install workspace packages --- .github/workflows/ci.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1be90b61..bca0feb7 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -23,7 +23,7 @@ jobs: enable-cache: true - name: Install dependencies - run: uv sync --group dev + run: uv sync --all-groups - name: Run ruff linter run: uv run ruff check . @@ -44,7 +44,7 @@ jobs: enable-cache: true - name: Install dependencies - run: uv sync --group dev + run: uv sync --all-groups - name: Run mypy run: uv run mypy packages/morphir/src packages/morphir-tools/src @@ -65,7 +65,7 @@ jobs: enable-cache: true - name: Install dependencies - run: uv sync --group test + run: uv sync --all-groups - name: Run pytest run: uv run pytest tests/ --cov=packages/morphir/src --cov=packages/morphir-tools/src --cov-report=xml From 7e19b944061a7e4ba82333539c297618899b9ca3 Mon Sep 17 00:00:00 2001 From: Damian Reeves <957246+DamianReeves@users.noreply.github.com> Date: Mon, 19 Jan 2026 17:10:53 -0600 Subject: [PATCH 4/6] fix(ci): Install workspace packages in editable mode for tests --- .github/workflows/ci.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index bca0feb7..73234061 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -65,7 +65,9 @@ jobs: enable-cache: true - name: Install dependencies - run: uv sync --all-groups + run: | + uv sync --all-groups + uv pip install -e packages/morphir -e packages/morphir-tools - name: Run pytest run: uv run pytest tests/ --cov=packages/morphir/src --cov=packages/morphir-tools/src --cov-report=xml From ff05ea9123cf29638d7c8302b8c10e22517fb06b Mon Sep 17 00:00:00 2001 From: Damian Reeves <957246+DamianReeves@users.noreply.github.com> Date: Mon, 19 Jan 2026 17:29:58 -0600 Subject: [PATCH 5/6] refactor(ci): Use mise tasks for consistent CI/local development - Add 'install' task to handle dependency sync and workspace package installation - Update CI workflow to use mise-action and mise tasks - Add XML coverage output to coverage task for CI reporting --- .config/mise/tasks/coverage | 2 +- .config/mise/tasks/install | 11 ++++++++ .github/workflows/ci.yml | 54 +++++++++++++------------------------ 3 files changed, 31 insertions(+), 36 deletions(-) create mode 100755 .config/mise/tasks/install diff --git a/.config/mise/tasks/coverage b/.config/mise/tasks/coverage index dbc4961c..9145ec1f 100755 --- a/.config/mise/tasks/coverage +++ b/.config/mise/tasks/coverage @@ -2,4 +2,4 @@ #MISE description="Run tests with coverage report" set -euo pipefail -uv run pytest tests/ --cov=packages/morphir/src --cov=packages/morphir-tools/src --cov-report=term-missing --cov-report=html +uv run pytest tests/ --cov=packages/morphir/src --cov=packages/morphir-tools/src --cov-report=term-missing --cov-report=html --cov-report=xml diff --git a/.config/mise/tasks/install b/.config/mise/tasks/install new file mode 100755 index 00000000..1f91d6cc --- /dev/null +++ b/.config/mise/tasks/install @@ -0,0 +1,11 @@ +#!/usr/bin/env bash +#MISE description="Install all dependencies and workspace packages" +set -euo pipefail + +echo "Syncing dependencies..." +uv sync --all-groups + +echo "Installing workspace packages in editable mode..." +uv pip install -e packages/morphir -e packages/morphir-tools + +echo "Install complete!" diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 73234061..d0ab8411 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -17,19 +17,17 @@ jobs: - name: Checkout repository uses: actions/checkout@v4 - - name: Set up uv - uses: astral-sh/setup-uv@v4 - with: - enable-cache: true + - name: Set up mise + uses: jdx/mise-action@v2 - name: Install dependencies - run: uv sync --all-groups + run: mise run install - name: Run ruff linter - run: uv run ruff check . + run: mise run lint - name: Check formatting - run: uv run ruff format --check . + run: mise run format-check typecheck: name: Type Check @@ -38,19 +36,14 @@ jobs: - name: Checkout repository uses: actions/checkout@v4 - - name: Set up uv - uses: astral-sh/setup-uv@v4 - with: - enable-cache: true + - name: Set up mise + uses: jdx/mise-action@v2 - name: Install dependencies - run: uv sync --all-groups - - - name: Run mypy - run: uv run mypy packages/morphir/src packages/morphir-tools/src + run: mise run install - - name: Run pyright - run: uv run pyright packages/morphir/src packages/morphir-tools/src + - name: Run type checkers + run: mise run typecheck test: name: Test @@ -59,21 +52,17 @@ jobs: - name: Checkout repository uses: actions/checkout@v4 - - name: Set up uv - uses: astral-sh/setup-uv@v4 - with: - enable-cache: true + - name: Set up mise + uses: jdx/mise-action@v2 - name: Install dependencies - run: | - uv sync --all-groups - uv pip install -e packages/morphir -e packages/morphir-tools + run: mise run install - name: Run pytest - run: uv run pytest tests/ --cov=packages/morphir/src --cov=packages/morphir-tools/src --cov-report=xml + run: mise run coverage - name: Run behave - run: uv run behave features/ + run: mise run test-bdd - name: Upload coverage to Codecov uses: codecov/codecov-action@v4 @@ -91,16 +80,11 @@ jobs: - name: Checkout repository uses: actions/checkout@v4 - - name: Set up uv - uses: astral-sh/setup-uv@v4 - with: - enable-cache: true - - - name: Build morphir package - run: uv build packages/morphir + - name: Set up mise + uses: jdx/mise-action@v2 - - name: Build morphir-tools package - run: uv build packages/morphir-tools + - name: Build packages + run: mise run build - name: Upload artifacts uses: actions/upload-artifact@v4 From 69568f82e26b95a27eea054957292575fb6804f2 Mon Sep 17 00:00:00 2001 From: Damian Reeves <957246+DamianReeves@users.noreply.github.com> Date: Mon, 19 Jan 2026 17:39:28 -0600 Subject: [PATCH 6/6] fix: Add future annotations to prevent NameError with TYPE_CHECKING imports Add 'from __future__ import annotations' to defer annotation evaluation, preventing NameError when Context type is only imported under TYPE_CHECKING. --- features/environment.py | 2 ++ features/steps/setup_steps.py | 2 ++ 2 files changed, 4 insertions(+) diff --git a/features/environment.py b/features/environment.py index 11583fa6..a4a88aff 100644 --- a/features/environment.py +++ b/features/environment.py @@ -4,6 +4,8 @@ the BDD test execution lifecycle. """ +from __future__ import annotations + from typing import TYPE_CHECKING if TYPE_CHECKING: diff --git a/features/steps/setup_steps.py b/features/steps/setup_steps.py index 57617d2d..0b77b960 100644 --- a/features/steps/setup_steps.py +++ b/features/steps/setup_steps.py @@ -1,5 +1,7 @@ """Step definitions for project setup verification.""" +from __future__ import annotations + from typing import TYPE_CHECKING, Any from behave import given, then, when