pytest-llm-assert 0.1.0__tar.gz → 0.2.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. pytest_llm_assert-0.2.0/.github/CODEOWNERS +8 -0
  2. pytest_llm_assert-0.2.0/.github/ISSUE_TEMPLATE/bug_report.md +40 -0
  3. pytest_llm_assert-0.2.0/.github/ISSUE_TEMPLATE/config.yml +8 -0
  4. pytest_llm_assert-0.2.0/.github/ISSUE_TEMPLATE/feature_request.md +22 -0
  5. pytest_llm_assert-0.2.0/.github/PULL_REQUEST_TEMPLATE.md +25 -0
  6. pytest_llm_assert-0.2.0/.github/dependabot.yml +27 -0
  7. {pytest_llm_assert-0.1.0 → pytest_llm_assert-0.2.0}/.github/workflows/ci.yml +13 -13
  8. pytest_llm_assert-0.2.0/.github/workflows/codeql.yml +42 -0
  9. pytest_llm_assert-0.2.0/.github/workflows/dependency-review.yml +23 -0
  10. {pytest_llm_assert-0.1.0 → pytest_llm_assert-0.2.0}/.github/workflows/release.yml +8 -8
  11. pytest_llm_assert-0.2.0/.github/workflows/stale.yml +35 -0
  12. pytest_llm_assert-0.2.0/.pre-commit-config.yaml +16 -0
  13. pytest_llm_assert-0.2.0/CODE_OF_CONDUCT.md +30 -0
  14. pytest_llm_assert-0.2.0/CONTRIBUTING.md +116 -0
  15. pytest_llm_assert-0.2.0/PKG-INFO +135 -0
  16. pytest_llm_assert-0.2.0/README.md +103 -0
  17. pytest_llm_assert-0.2.0/SECURITY.md +27 -0
  18. pytest_llm_assert-0.2.0/docs/GITHUB_SETUP_GUIDE.md +833 -0
  19. pytest_llm_assert-0.2.0/docs/README.md +15 -0
  20. pytest_llm_assert-0.2.0/docs/api-reference.md +150 -0
  21. pytest_llm_assert-0.2.0/docs/comparing-models.md +25 -0
  22. pytest_llm_assert-0.2.0/docs/configuration.md +38 -0
  23. pytest_llm_assert-0.2.0/examples/conftest.py +21 -0
  24. {pytest_llm_assert-0.1.0 → pytest_llm_assert-0.2.0}/pyproject.toml +10 -8
  25. pytest_llm_assert-0.2.0/src/pytest_llm_assert/__init__.py +6 -0
  26. {pytest_llm_assert-0.1.0 → pytest_llm_assert-0.2.0}/src/pytest_llm_assert/core.py +67 -14
  27. pytest_llm_assert-0.2.0/src/pytest_llm_assert/prompts/system_prompt.md +4 -0
  28. {pytest_llm_assert-0.1.0 → pytest_llm_assert-0.2.0}/tests/integration/test_llm_integration.py +8 -6
  29. pytest_llm_assert-0.2.0/tests/unit/test_assertion_result.py +53 -0
  30. pytest_llm_assert-0.2.0/tests/unit/test_azure_auth.py +163 -0
  31. pytest_llm_assert-0.2.0/tests/unit/test_error_handling.py +66 -0
  32. pytest_llm_assert-0.2.0/tests/unit/test_fixture_integration.py +12 -0
  33. pytest_llm_assert-0.2.0/tests/unit/test_llm_assert_core.py +199 -0
  34. pytest_llm_assert-0.2.0/tests/unit/test_llm_response.py +35 -0
  35. pytest_llm_assert-0.2.0/tests/unit/test_plugin.py +93 -0
  36. pytest_llm_assert-0.2.0/tests/unit/test_response_parsing.py +187 -0
  37. {pytest_llm_assert-0.1.0 → pytest_llm_assert-0.2.0}/uv.lock +241 -11
  38. pytest_llm_assert-0.1.0/PKG-INFO +0 -246
  39. pytest_llm_assert-0.1.0/README.md +0 -216
  40. pytest_llm_assert-0.1.0/src/pytest_llm_assert/__init__.py +0 -6
  41. pytest_llm_assert-0.1.0/tests/unit/test_llm_assert.py +0 -214
  42. {pytest_llm_assert-0.1.0 → pytest_llm_assert-0.2.0}/.env.example +0 -0
  43. {pytest_llm_assert-0.1.0 → pytest_llm_assert-0.2.0}/.gitignore +0 -0
  44. {pytest_llm_assert-0.1.0 → pytest_llm_assert-0.2.0}/LICENSE +0 -0
  45. {pytest_llm_assert-0.1.0 → pytest_llm_assert-0.2.0}/examples/README.md +0 -0
  46. {pytest_llm_assert-0.1.0 → pytest_llm_assert-0.2.0}/examples/pytest_conftest.py +0 -0
  47. {pytest_llm_assert-0.1.0 → pytest_llm_assert-0.2.0}/examples/test_basic.py +0 -0
  48. {pytest_llm_assert-0.1.0 → pytest_llm_assert-0.2.0}/examples/test_compare_models.py +0 -0
  49. {pytest_llm_assert-0.1.0 → pytest_llm_assert-0.2.0}/src/pytest_llm_assert/plugin.py +0 -0
  50. {pytest_llm_assert-0.1.0 → pytest_llm_assert-0.2.0}/tests/__init__.py +0 -0
  51. {pytest_llm_assert-0.1.0 → pytest_llm_assert-0.2.0}/tests/integration/__init__.py +0 -0
  52. {pytest_llm_assert-0.1.0 → pytest_llm_assert-0.2.0}/tests/unit/__init__.py +0 -0
@@ -0,0 +1,8 @@
1
+ # Default owners for everything in the repo
2
+ * @sbroenne
3
+
4
+ # Python source code
5
+ /src/ @sbroenne
6
+
7
+ # CI/CD configuration
8
+ /.github/ @sbroenne
@@ -0,0 +1,40 @@
1
+ ---
2
+ name: Bug report
3
+ about: Report a bug to help us improve
4
+ title: '[BUG] '
5
+ labels: bug
6
+ assignees: ''
7
+ ---
8
+
9
+ ## Bug Description
10
+ A clear description of what the bug is.
11
+
12
+ ## To Reproduce
13
+ Steps to reproduce:
14
+ 1. ...
15
+ 2. ...
16
+
17
+ ## Expected Behavior
18
+ What you expected to happen.
19
+
20
+ ## Actual Behavior
21
+ What actually happened.
22
+
23
+ ## Environment
24
+ - pytest-llm-assert version:
25
+ - Python version:
26
+ - OS:
27
+ - LLM provider/model:
28
+
29
+ ## Code Example
30
+ ```python
31
+ # Minimal code to reproduce the issue
32
+ ```
33
+
34
+ ## Error Output
35
+ ```
36
+ # Paste any error messages or tracebacks
37
+ ```
38
+
39
+ ## Additional Context
40
+ Any other context about the problem.
@@ -0,0 +1,8 @@
1
+ blank_issues_enabled: false
2
+ contact_links:
3
+ - name: Documentation
4
+ url: https://github.com/sbroenne/pytest-llm-assert#readme
5
+ about: Check the documentation before opening an issue
6
+ - name: Discussions
7
+ url: https://github.com/sbroenne/pytest-llm-assert/discussions
8
+ about: Ask questions and discuss ideas
@@ -0,0 +1,22 @@
1
+ ---
2
+ name: Feature request
3
+ about: Suggest an idea for this project
4
+ title: '[FEATURE] '
5
+ labels: enhancement
6
+ assignees: ''
7
+ ---
8
+
9
+ ## Problem
10
+ Describe the problem or limitation you're facing.
11
+
12
+ ## Proposed Solution
13
+ Describe what you'd like to happen.
14
+
15
+ ## Alternatives Considered
16
+ Describe any alternative solutions you've considered.
17
+
18
+ ## Use Case
19
+ Explain how this feature would benefit users.
20
+
21
+ ## Additional Context
22
+ Any other context, examples, or screenshots.
@@ -0,0 +1,25 @@
1
+ ## Description
2
+
3
+ Brief description of the changes.
4
+
5
+ ## Type of Change
6
+
7
+ - [ ] Bug fix (non-breaking change that fixes an issue)
8
+ - [ ] New feature (non-breaking change that adds functionality)
9
+ - [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected)
10
+ - [ ] Documentation update
11
+
12
+ ## Checklist
13
+
14
+ - [ ] I have run `pre-commit run --all-files` and all checks pass
15
+ - [ ] I have added tests that prove my fix/feature works
16
+ - [ ] I have updated the documentation if needed
17
+ - [ ] My changes generate no new warnings
18
+
19
+ ## Testing
20
+
21
+ Describe the tests you added or ran.
22
+
23
+ ## Related Issues
24
+
25
+ Fixes #(issue number)
@@ -0,0 +1,27 @@
1
+ version: 2
2
+ updates:
3
+ # Python dependencies
4
+ - package-ecosystem: "pip"
5
+ directory: "/"
6
+ schedule:
7
+ interval: "weekly"
8
+ day: "monday"
9
+ open-pull-requests-limit: 5
10
+ labels:
11
+ - "dependencies"
12
+ - "python"
13
+ commit-message:
14
+ prefix: "chore(deps)"
15
+
16
+ # GitHub Actions
17
+ - package-ecosystem: "github-actions"
18
+ directory: "/"
19
+ schedule:
20
+ interval: "weekly"
21
+ day: "monday"
22
+ open-pull-requests-limit: 5
23
+ labels:
24
+ - "dependencies"
25
+ - "github-actions"
26
+ commit-message:
27
+ prefix: "chore(deps)"
@@ -2,7 +2,7 @@ name: CI
2
2
 
3
3
  on:
4
4
  push:
5
- branches: [main]
5
+ branches: [main, 'feature/**', 'fix/**', 'dev/**']
6
6
  pull_request:
7
7
  branches: [main]
8
8
  workflow_dispatch:
@@ -12,15 +12,15 @@ jobs:
12
12
  name: Lint
13
13
  runs-on: ubuntu-latest
14
14
  steps:
15
- - uses: actions/checkout@v4
15
+ - uses: actions/checkout@v6
16
16
 
17
17
  - name: Install uv
18
- uses: astral-sh/setup-uv@v4
18
+ uses: astral-sh/setup-uv@v7
19
19
  with:
20
20
  version: "latest"
21
21
 
22
22
  - name: Set up Python
23
- uses: actions/setup-python@v5
23
+ uses: actions/setup-python@v6
24
24
  with:
25
25
  python-version: "3.13"
26
26
 
@@ -37,15 +37,15 @@ jobs:
37
37
  name: Type Check
38
38
  runs-on: ubuntu-latest
39
39
  steps:
40
- - uses: actions/checkout@v4
40
+ - uses: actions/checkout@v6
41
41
 
42
42
  - name: Install uv
43
- uses: astral-sh/setup-uv@v4
43
+ uses: astral-sh/setup-uv@v7
44
44
  with:
45
45
  version: "latest"
46
46
 
47
47
  - name: Set up Python
48
- uses: actions/setup-python@v5
48
+ uses: actions/setup-python@v6
49
49
  with:
50
50
  python-version: "3.13"
51
51
 
@@ -63,15 +63,15 @@ jobs:
63
63
  matrix:
64
64
  python-version: ["3.11", "3.12", "3.13"]
65
65
  steps:
66
- - uses: actions/checkout@v4
66
+ - uses: actions/checkout@v6
67
67
 
68
68
  - name: Install uv
69
- uses: astral-sh/setup-uv@v4
69
+ uses: astral-sh/setup-uv@v7
70
70
  with:
71
71
  version: "latest"
72
72
 
73
73
  - name: Set up Python ${{ matrix.python-version }}
74
- uses: actions/setup-python@v5
74
+ uses: actions/setup-python@v6
75
75
  with:
76
76
  python-version: ${{ matrix.python-version }}
77
77
 
@@ -85,15 +85,15 @@ jobs:
85
85
  name: Smoke Test
86
86
  runs-on: ubuntu-latest
87
87
  steps:
88
- - uses: actions/checkout@v4
88
+ - uses: actions/checkout@v6
89
89
 
90
90
  - name: Install uv
91
- uses: astral-sh/setup-uv@v4
91
+ uses: astral-sh/setup-uv@v7
92
92
  with:
93
93
  version: "latest"
94
94
 
95
95
  - name: Set up Python
96
- uses: actions/setup-python@v5
96
+ uses: actions/setup-python@v6
97
97
  with:
98
98
  python-version: "3.13"
99
99
 
@@ -0,0 +1,42 @@
1
+ name: CodeQL
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+ branches: [main]
8
+ schedule:
9
+ # Run weekly on Sundays at 00:00 UTC
10
+ - cron: "0 0 * * 0"
11
+
12
+ jobs:
13
+ analyze:
14
+ name: Analyze
15
+ runs-on: ubuntu-latest
16
+ permissions:
17
+ actions: read
18
+ contents: read
19
+ security-events: write
20
+
21
+ strategy:
22
+ fail-fast: false
23
+ matrix:
24
+ language: [python]
25
+
26
+ steps:
27
+ - name: Checkout repository
28
+ uses: actions/checkout@v6
29
+
30
+ - name: Initialize CodeQL
31
+ uses: github/codeql-action/init@v4
32
+ with:
33
+ languages: ${{ matrix.language }}
34
+ queries: security-extended,security-and-quality
35
+
36
+ - name: Autobuild
37
+ uses: github/codeql-action/autobuild@v4
38
+
39
+ - name: Perform CodeQL Analysis
40
+ uses: github/codeql-action/analyze@v4
41
+ with:
42
+ category: "/language:${{ matrix.language }}"
@@ -0,0 +1,23 @@
1
+ name: Dependency Review
2
+
3
+ on:
4
+ pull_request:
5
+ branches: [main]
6
+
7
+ permissions:
8
+ contents: read
9
+ pull-requests: write
10
+
11
+ jobs:
12
+ dependency-review:
13
+ name: Dependency Review
14
+ runs-on: ubuntu-latest
15
+ steps:
16
+ - name: Checkout repository
17
+ uses: actions/checkout@v6
18
+
19
+ - name: Dependency Review
20
+ uses: actions/dependency-review-action@v4
21
+ with:
22
+ fail-on-severity: high
23
+ comment-summary-in-pr: always
@@ -10,15 +10,15 @@ jobs:
10
10
  name: Build Package
11
11
  runs-on: ubuntu-latest
12
12
  steps:
13
- - uses: actions/checkout@v4
13
+ - uses: actions/checkout@v6
14
14
 
15
15
  - name: Install uv
16
- uses: astral-sh/setup-uv@v4
16
+ uses: astral-sh/setup-uv@v7
17
17
  with:
18
18
  version: "latest"
19
19
 
20
20
  - name: Set up Python
21
- uses: actions/setup-python@v5
21
+ uses: actions/setup-python@v6
22
22
  with:
23
23
  python-version: "3.13"
24
24
 
@@ -50,13 +50,13 @@ jobs:
50
50
  needs: build
51
51
  steps:
52
52
  - name: Download build artifacts
53
- uses: actions/download-artifact@v4
53
+ uses: actions/download-artifact@v7
54
54
  with:
55
55
  name: dist
56
56
  path: dist/
57
57
 
58
58
  - name: Set up Python
59
- uses: actions/setup-python@v5
59
+ uses: actions/setup-python@v6
60
60
  with:
61
61
  python-version: "3.13"
62
62
 
@@ -78,7 +78,7 @@ jobs:
78
78
  id-token: write
79
79
  steps:
80
80
  - name: Download build artifacts
81
- uses: actions/download-artifact@v4
81
+ uses: actions/download-artifact@v7
82
82
  with:
83
83
  name: dist
84
84
  path: dist/
@@ -93,10 +93,10 @@ jobs:
93
93
  permissions:
94
94
  contents: write
95
95
  steps:
96
- - uses: actions/checkout@v4
96
+ - uses: actions/checkout@v6
97
97
 
98
98
  - name: Download build artifacts
99
- uses: actions/download-artifact@v4
99
+ uses: actions/download-artifact@v7
100
100
  with:
101
101
  name: dist
102
102
  path: dist/
@@ -0,0 +1,35 @@
1
+ name: Stale Issues and PRs
2
+
3
+ on:
4
+ schedule:
5
+ - cron: "0 0 * * *" # Run daily at midnight UTC
6
+ workflow_dispatch:
7
+
8
+ permissions:
9
+ issues: write
10
+ pull-requests: write
11
+
12
+ jobs:
13
+ stale:
14
+ runs-on: ubuntu-latest
15
+ steps:
16
+ - uses: actions/stale@v10
17
+ with:
18
+ stale-issue-message: >
19
+ This issue has been automatically marked as stale because it has not had
20
+ recent activity. It will be closed if no further activity occurs within 7 days.
21
+ Thank you for your contributions!
22
+ stale-pr-message: >
23
+ This pull request has been automatically marked as stale because it has not had
24
+ recent activity. It will be closed if no further activity occurs within 7 days.
25
+ close-issue-message: >
26
+ This issue was closed because it has been stale for 7 days with no activity.
27
+ Feel free to reopen if this is still relevant.
28
+ close-pr-message: >
29
+ This pull request was closed because it has been stale for 7 days with no activity.
30
+ days-before-stale: 30
31
+ days-before-close: 7
32
+ stale-issue-label: "stale"
33
+ stale-pr-label: "stale"
34
+ exempt-issue-labels: "pinned,security,bug"
35
+ exempt-pr-labels: "pinned,security"
@@ -0,0 +1,16 @@
1
+ repos:
2
+ - repo: https://github.com/astral-sh/ruff-pre-commit
3
+ rev: v0.14.0
4
+ hooks:
5
+ - id: ruff
6
+ args: [--fix]
7
+ - id: ruff-format
8
+
9
+ - repo: local
10
+ hooks:
11
+ - id: pyright
12
+ name: pyright
13
+ entry: pyright
14
+ language: system
15
+ types: [python]
16
+ pass_filenames: false
@@ -0,0 +1,30 @@
1
+ # Code of Conduct
2
+
3
+ ## Our Pledge
4
+
5
+ We pledge to make participation in our project a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.
6
+
7
+ ## Our Standards
8
+
9
+ Examples of behavior that contributes to a positive environment:
10
+
11
+ - Using welcoming and inclusive language
12
+ - Being respectful of differing viewpoints and experiences
13
+ - Gracefully accepting constructive criticism
14
+ - Focusing on what is best for the community
15
+ - Showing empathy towards other community members
16
+
17
+ Examples of unacceptable behavior:
18
+
19
+ - Trolling, insulting/derogatory comments, and personal or political attacks
20
+ - Public or private harassment
21
+ - Publishing others' private information without explicit permission
22
+ - Other conduct which could reasonably be considered inappropriate
23
+
24
+ ## Enforcement
25
+
26
+ Project maintainers are responsible for clarifying standards of acceptable behavior and will take appropriate and fair corrective action in response to any instances of unacceptable behavior.
27
+
28
+ ## Attribution
29
+
30
+ This Code of Conduct is adapted from the [Contributor Covenant](https://www.contributor-covenant.org/), version 2.1.
@@ -0,0 +1,116 @@
1
+ # Contributing to pytest-llm-assert
2
+
3
+ ## Development Setup
4
+
5
+ 1. Clone the repository:
6
+ ```bash
7
+ git clone https://github.com/sbroenne/pytest-llm-assert.git
8
+ cd pytest-llm-assert
9
+ ```
10
+
11
+ 2. Create a virtual environment and install dependencies:
12
+ ```bash
13
+ python -m venv .venv
14
+ source .venv/bin/activate # On Windows: .venv\Scripts\activate
15
+ pip install -e ".[dev]"
16
+ ```
17
+
18
+ 3. Install pre-commit hooks:
19
+ ```bash
20
+ pre-commit install
21
+ ```
22
+
23
+ ## Code Quality
24
+
25
+ This project uses automated tools to maintain code quality:
26
+
27
+ - **[Ruff](https://docs.astral.sh/ruff/)** — Linting and formatting
28
+ - **[Pyright](https://github.com/microsoft/pyright)** — Type checking
29
+ - **[pre-commit](https://pre-commit.com/)** — Git hooks for automated checks
30
+
31
+ ### Running Checks Manually
32
+
33
+ ```bash
34
+ # Run all pre-commit hooks
35
+ pre-commit run --all-files
36
+
37
+ # Or run individual tools
38
+ ruff check . # Linting
39
+ ruff format . # Formatting
40
+ pyright # Type checking
41
+ ```
42
+
43
+ ### Pre-commit Hooks
44
+
45
+ Pre-commit hooks run automatically on `git commit`. If a hook fails, fix the issues and commit again.
46
+
47
+ The hooks will:
48
+ 1. **ruff** — Auto-fix linting issues where possible
49
+ 2. **ruff-format** — Format code consistently
50
+ 3. **pyright** — Check types
51
+
52
+ ## Running Tests
53
+
54
+ ```bash
55
+ # Run unit tests
56
+ pytest tests/unit/ -v
57
+
58
+ # Run all tests (requires LLM credentials)
59
+ pytest -v
60
+
61
+ # Run integration tests only
62
+ pytest -m integration -v
63
+ ```
64
+
65
+ ### Integration Tests
66
+
67
+ Integration tests require LLM provider credentials. Set up at least one:
68
+
69
+ ```bash
70
+ # Azure OpenAI (uses Entra ID - no API key needed)
71
+ export AZURE_OPENAI_ENDPOINT=https://your-resource.openai.azure.com
72
+ az login
73
+
74
+ # Google Vertex AI
75
+ export GOOGLE_CLOUD_PROJECT=your-project-id
76
+ gcloud auth application-default login
77
+ ```
78
+
79
+ ## Project Structure
80
+
81
+ ```
82
+ pytest-llm-assert/
83
+ ├── src/pytest_llm_assert/
84
+ │ ├── __init__.py # Package exports
85
+ │ ├── core.py # LLMAssert implementation
86
+ │ └── plugin.py # pytest plugin (fixtures, CLI options)
87
+ ├── tests/
88
+ │ ├── unit/ # Unit tests (mocked LLM calls)
89
+ │ └── integration/ # Integration tests (real LLM calls)
90
+ ├── examples/ # Example usage patterns
91
+ ├── pyproject.toml # Project configuration
92
+ └── .pre-commit-config.yaml
93
+ ```
94
+
95
+ ## Making Changes
96
+
97
+ 1. Create a branch for your changes
98
+ 2. Make your changes
99
+ 3. Ensure all checks pass: `pre-commit run --all-files`
100
+ 4. Run tests: `pytest tests/unit/ -v`
101
+ 5. Submit a pull request
102
+
103
+ All PRs are **squash merged** to keep a clean commit history on main.
104
+
105
+ ## Code Style
106
+
107
+ - Follow [PEP 8](https://peps.python.org/pep-0008/) (enforced by Ruff)
108
+ - Use type hints for all public APIs
109
+ - Keep functions focused and small
110
+ - Write docstrings for public classes and methods
111
+
112
+ ## Releasing
113
+
114
+ 1. Update version in `src/pytest_llm_assert/__init__.py` and `pyproject.toml`
115
+ 2. Create a git tag: `git tag v0.x.x`
116
+ 3. Push: `git push origin main --tags`
@@ -0,0 +1,135 @@
1
+ Metadata-Version: 2.4
2
+ Name: pytest-llm-assert
3
+ Version: 0.2.0
4
+ Summary: Simple LLM-powered assertions for any pytest test
5
+ Project-URL: Homepage, https://github.com/sbroenne/pytest-llm-assert
6
+ Project-URL: Documentation, https://github.com/sbroenne/pytest-llm-assert#readme
7
+ Project-URL: Repository, https://github.com/sbroenne/pytest-llm-assert
8
+ Author: Stefan Broenner
9
+ License-Expression: MIT
10
+ License-File: LICENSE
11
+ Keywords: ai,assertions,llm,pytest,testing
12
+ Classifier: Development Status :: 3 - Alpha
13
+ Classifier: Framework :: Pytest
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: License :: OSI Approved :: MIT License
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Programming Language :: Python :: 3.11
18
+ Classifier: Programming Language :: Python :: 3.12
19
+ Classifier: Programming Language :: Python :: 3.13
20
+ Requires-Python: >=3.11
21
+ Requires-Dist: azure-identity>=1.25
22
+ Requires-Dist: litellm>=1.81
23
+ Requires-Dist: pytest>=9.0
24
+ Provides-Extra: dev
25
+ Requires-Dist: pre-commit>=4.5; extra == 'dev'
26
+ Requires-Dist: pyright>=1.1.408; extra == 'dev'
27
+ Requires-Dist: pytest-cov>=6.0; extra == 'dev'
28
+ Requires-Dist: pytest>=9.0; extra == 'dev'
29
+ Requires-Dist: python-dotenv>=1.2; extra == 'dev'
30
+ Requires-Dist: ruff>=0.14; extra == 'dev'
31
+ Description-Content-Type: text/markdown
32
+
33
+ # pytest-llm-assert
34
+
35
+ [![PyPI version](https://img.shields.io/pypi/v/pytest-llm-assert)](https://pypi.org/project/pytest-llm-assert/)
36
+ [![Python versions](https://img.shields.io/pypi/pyversions/pytest-llm-assert)](https://pypi.org/project/pytest-llm-assert/)
37
+ [![CI](https://github.com/sbroenne/pytest-llm-assert/actions/workflows/ci.yml/badge.svg)](https://github.com/sbroenne/pytest-llm-assert/actions/workflows/ci.yml)
38
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
39
+
40
+ **Natural language assertions for pytest.**
41
+
42
+ Testing a text-to-SQL agent? Validating LLM-generated code? Checking if error messages are helpful? Now you can:
43
+
44
+ ```python
45
+ def test_sql_agent_output(llm):
46
+ sql = my_agent.generate("Get names of users over 21")
47
+
48
+ assert llm(sql, "Is this a valid SQL query that selects user names filtered by age > 21?")
49
+ ```
50
+
51
+ The LLM evaluates your criterion and returns pass/fail — no regex, no parsing, no exact string matching.
52
+
53
+ ## Features
54
+
55
+ - **Semantic assertions** — Assert meaning, not exact strings
56
+ - **100+ LLM providers** — OpenAI, Azure, Anthropic, Ollama, Vertex AI, Bedrock via [LiteLLM](https://docs.litellm.ai/)
57
+ - **pytest native** — Works as a standard pytest plugin/fixture
58
+ - **Response introspection** — Access tokens, cost, and reasoning via `llm.response`
59
+
60
+ ## Installation
61
+
62
+ ```bash
63
+ pip install pytest-llm-assert
64
+ ```
65
+
66
+ ## Quick Start
67
+
68
+ ```python
69
+ # conftest.py
70
+ import pytest
71
+ from pytest_llm_assert import LLMAssert
72
+
73
+ @pytest.fixture
74
+ def llm():
75
+ return LLMAssert(model="openai/gpt-5-mini")
76
+ ```
77
+
78
+ ```python
79
+ # test_my_agent.py
80
+ def test_generated_sql_is_correct(llm):
81
+ sql = "SELECT name FROM users WHERE age > 21 ORDER BY name"
82
+ assert llm(sql, "Is this a valid SELECT query that returns names of users over 21?")
83
+
84
+ def test_error_message_is_helpful(llm):
85
+ error = "ValidationError: 'port' must be an integer, got 'abc'"
86
+ assert llm(error, "Does this explain what went wrong and how to fix it?")
87
+
88
+ def test_summary_captures_key_points(llm):
89
+ summary = generate_summary(document)
90
+ assert llm(summary, "Does this mention the contract duration and parties involved?")
91
+ ```
92
+
93
+ ## Setup
94
+
95
+ Works out of the box with cloud identity — no API keys to manage:
96
+
97
+ ```bash
98
+ # Azure (Entra ID)
99
+ export AZURE_API_BASE=https://your-resource.openai.azure.com
100
+ az login
101
+
102
+ # Google Cloud (Vertex AI)
103
+ gcloud auth application-default login
104
+
105
+ # AWS (Bedrock)
106
+ aws configure # Uses IAM credentials
107
+ ```
108
+
109
+ Supports 100+ providers via [LiteLLM](https://docs.litellm.ai/docs/providers) — including API key auth for OpenAI, Anthropic, Ollama, and more.
110
+
111
+ ## Documentation
112
+
113
+ - **[Configuration](docs/configuration.md)** — All providers, CLI options, environment variables
114
+ - **[API Reference](docs/api-reference.md)** — Full API documentation
115
+ - **[Comparing Judge Models](docs/comparing-models.md)** — Evaluate which LLM works best for your assertions
116
+ - **[Examples](examples/)** — Working pytest examples
117
+
118
+ ## Related
119
+
120
+ - **[pytest-aitest](https://github.com/sbroenne/pytest-aitest)** — Full framework for testing MCP servers, CLIs, and AI agents
121
+ - **[Contributing](CONTRIBUTING.md)** — Development setup and guidelines
122
+
123
+ ## Requirements
124
+
125
+ - Python 3.11+
126
+ - pytest 8.0+
127
+ - An LLM (OpenAI, Azure, Anthropic, etc.) or local [Ollama](https://ollama.ai/)
128
+
129
+ ## Security
130
+
131
+ - **Sensitive data**: Test content is sent to LLM providers — consider data policies
132
+
133
+ ## License
134
+
135
+ MIT