leapocr 0.0.1__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.
- leapocr-0.0.1/.github/PULL_REQUEST_TEMPLATE.md +54 -0
- leapocr-0.0.1/.github/PYPI_SETUP.md +134 -0
- leapocr-0.0.1/.github/workflows/ci.yml +130 -0
- leapocr-0.0.1/.github/workflows/integration-tests.yml +50 -0
- leapocr-0.0.1/.github/workflows/release.yml +123 -0
- leapocr-0.0.1/.gitignore +216 -0
- leapocr-0.0.1/.python-version +1 -0
- leapocr-0.0.1/CHANGELOG.md +57 -0
- leapocr-0.0.1/CONTRIBUTING.md +376 -0
- leapocr-0.0.1/IMPLEMENTATION_SUMMARY.md +362 -0
- leapocr-0.0.1/Makefile +158 -0
- leapocr-0.0.1/PKG-INFO +577 -0
- leapocr-0.0.1/QUICKSTART.md +276 -0
- leapocr-0.0.1/README.md +545 -0
- leapocr-0.0.1/RELEASING.md +191 -0
- leapocr-0.0.1/SDK_IMPLEMENTATION_PLAN.md +1890 -0
- leapocr-0.0.1/examples/README.md +234 -0
- leapocr-0.0.1/examples/advanced/batch_processing.py +102 -0
- leapocr-0.0.1/examples/advanced/custom_config.py +116 -0
- leapocr-0.0.1/examples/advanced/schema_extraction.py +164 -0
- leapocr-0.0.1/examples/basic/process_file.py +72 -0
- leapocr-0.0.1/examples/basic/process_url.py +91 -0
- leapocr-0.0.1/examples/error_handling/error_types.py +201 -0
- leapocr-0.0.1/examples/error_handling/timeout_handling.py +172 -0
- leapocr-0.0.1/leapocr/__init__.py +91 -0
- leapocr-0.0.1/leapocr/_internal/__init__.py +1 -0
- leapocr-0.0.1/leapocr/_internal/polling.py +130 -0
- leapocr-0.0.1/leapocr/_internal/retry.py +101 -0
- leapocr-0.0.1/leapocr/_internal/upload.py +118 -0
- leapocr-0.0.1/leapocr/_internal/utils.py +51 -0
- leapocr-0.0.1/leapocr/_internal/validation.py +172 -0
- leapocr-0.0.1/leapocr/client.py +96 -0
- leapocr-0.0.1/leapocr/config.py +59 -0
- leapocr-0.0.1/leapocr/errors.py +155 -0
- leapocr-0.0.1/leapocr/generated/.openapi-generator/FILES +89 -0
- leapocr-0.0.1/leapocr/generated/.openapi-generator/VERSION +1 -0
- leapocr-0.0.1/leapocr/generated/.openapi-generator-ignore +23 -0
- leapocr-0.0.1/leapocr/generated/leapocr/__init__.py +0 -0
- leapocr-0.0.1/leapocr/generated/leapocr/generated/__init__.py +202 -0
- leapocr-0.0.1/leapocr/generated/leapocr/generated/api/__init__.py +15 -0
- leapocr-0.0.1/leapocr/generated/leapocr/generated/api/analytics_api.py +868 -0
- leapocr-0.0.1/leapocr/generated/leapocr/generated/api/authentication_api.py +172 -0
- leapocr-0.0.1/leapocr/generated/leapocr/generated/api/credits_api.py +653 -0
- leapocr-0.0.1/leapocr/generated/leapocr/generated/api/health_api.py +161 -0
- leapocr-0.0.1/leapocr/generated/leapocr/generated/api/jobs_api.py +836 -0
- leapocr-0.0.1/leapocr/generated/leapocr/generated/api/models_api.py +161 -0
- leapocr-0.0.1/leapocr/generated/leapocr/generated/api/ocr_api.py +863 -0
- leapocr-0.0.1/leapocr/generated/leapocr/generated/api/sdk_api.py +744 -0
- leapocr-0.0.1/leapocr/generated/leapocr/generated/api/templates_api.py +1006 -0
- leapocr-0.0.1/leapocr/generated/leapocr/generated/api/upload_api.py +465 -0
- leapocr-0.0.1/leapocr/generated/leapocr/generated/api/webhooks_api.py +324 -0
- leapocr-0.0.1/leapocr/generated/leapocr/generated/api_client.py +738 -0
- leapocr-0.0.1/leapocr/generated/leapocr/generated/api_response.py +25 -0
- leapocr-0.0.1/leapocr/generated/leapocr/generated/configuration.py +476 -0
- leapocr-0.0.1/leapocr/generated/leapocr/generated/exceptions.py +167 -0
- leapocr-0.0.1/leapocr/generated/leapocr/generated/models/__init__.py +84 -0
- leapocr-0.0.1/leapocr/generated/leapocr/generated/models/analytics_credits_overview.py +82 -0
- leapocr-0.0.1/leapocr/generated/leapocr/generated/models/analytics_credits_timeseries_point.py +82 -0
- leapocr-0.0.1/leapocr/generated/leapocr/generated/models/analytics_credits_usage_response.py +102 -0
- leapocr-0.0.1/leapocr/generated/leapocr/generated/models/analytics_job_overview.py +94 -0
- leapocr-0.0.1/leapocr/generated/leapocr/generated/models/analytics_job_timeseries_point.py +88 -0
- leapocr-0.0.1/leapocr/generated/leapocr/generated/models/analytics_jobs_timeseries_get200_response.py +86 -0
- leapocr-0.0.1/leapocr/generated/leapocr/generated/models/analytics_model_usage_stat.py +78 -0
- leapocr-0.0.1/leapocr/generated/leapocr/generated/models/analytics_overview_response.py +100 -0
- leapocr-0.0.1/leapocr/generated/leapocr/generated/models/analytics_page_overview.py +82 -0
- leapocr-0.0.1/leapocr/generated/leapocr/generated/models/analytics_page_timeseries_point.py +84 -0
- leapocr-0.0.1/leapocr/generated/leapocr/generated/models/analytics_pages_timeseries_get200_response.py +86 -0
- leapocr-0.0.1/leapocr/generated/leapocr/generated/models/analytics_range.py +80 -0
- leapocr-0.0.1/leapocr/generated/leapocr/generated/models/analytics_template_stat.py +82 -0
- leapocr-0.0.1/leapocr/generated/leapocr/generated/models/analytics_top_templates_response.py +86 -0
- leapocr-0.0.1/leapocr/generated/leapocr/generated/models/analytics_webhook_summary.py +82 -0
- leapocr-0.0.1/leapocr/generated/leapocr/generated/models/auth_auth_response.py +81 -0
- leapocr-0.0.1/leapocr/generated/leapocr/generated/models/credits_active_meter_response.py +82 -0
- leapocr-0.0.1/leapocr/generated/leapocr/generated/models/credits_active_subscription_response.py +88 -0
- leapocr-0.0.1/leapocr/generated/leapocr/generated/models/credits_catalog_benefit.py +74 -0
- leapocr-0.0.1/leapocr/generated/leapocr/generated/models/credits_catalog_price.py +76 -0
- leapocr-0.0.1/leapocr/generated/leapocr/generated/models/credits_catalog_product.py +96 -0
- leapocr-0.0.1/leapocr/generated/leapocr/generated/models/credits_credit_balance_response.py +120 -0
- leapocr-0.0.1/leapocr/generated/leapocr/generated/models/credits_credit_transaction_organization_response.py +102 -0
- leapocr-0.0.1/leapocr/generated/leapocr/generated/models/credits_credit_transaction_project_response.py +102 -0
- leapocr-0.0.1/leapocr/generated/leapocr/generated/models/credits_credit_transactions_response_credits_credit_transaction_organization_response.py +86 -0
- leapocr-0.0.1/leapocr/generated/leapocr/generated/models/credits_credit_transactions_response_credits_credit_transaction_project_response.py +86 -0
- leapocr-0.0.1/leapocr/generated/leapocr/generated/models/credits_granted_benefit_response.py +82 -0
- leapocr-0.0.1/leapocr/generated/leapocr/generated/models/credits_pagination_info.py +76 -0
- leapocr-0.0.1/leapocr/generated/leapocr/generated/models/credits_product_catalog.py +89 -0
- leapocr-0.0.1/leapocr/generated/leapocr/generated/models/health_health_check.py +78 -0
- leapocr-0.0.1/leapocr/generated/leapocr/generated/models/health_health_status.py +97 -0
- leapocr-0.0.1/leapocr/generated/leapocr/generated/models/health_health_summary.py +78 -0
- leapocr-0.0.1/leapocr/generated/leapocr/generated/models/jobs_job_list_item.py +100 -0
- leapocr-0.0.1/leapocr/generated/leapocr/generated/models/jobs_job_management_response.py +82 -0
- leapocr-0.0.1/leapocr/generated/leapocr/generated/models/jobs_job_response.py +102 -0
- leapocr-0.0.1/leapocr/generated/leapocr/generated/models/jobs_job_status_response.py +90 -0
- leapocr-0.0.1/leapocr/generated/leapocr/generated/models/jobs_jobs_list_response.py +86 -0
- leapocr-0.0.1/leapocr/generated/leapocr/generated/models/jobs_pagination_info.py +78 -0
- leapocr-0.0.1/leapocr/generated/leapocr/generated/models/jobs_restart_job_request.py +74 -0
- leapocr-0.0.1/leapocr/generated/leapocr/generated/models/jobs_retry_job_request.py +74 -0
- leapocr-0.0.1/leapocr/generated/leapocr/generated/models/jobs_workflow_job_status_info.py +80 -0
- leapocr-0.0.1/leapocr/generated/leapocr/generated/models/jobs_workflow_progress_info.py +80 -0
- leapocr-0.0.1/leapocr/generated/leapocr/generated/models/jobs_workflow_status_info.py +104 -0
- leapocr-0.0.1/leapocr/generated/leapocr/generated/models/models_list_model_response.py +80 -0
- leapocr-0.0.1/leapocr/generated/leapocr/generated/models/models_list_models_list_response.py +82 -0
- leapocr-0.0.1/leapocr/generated/leapocr/generated/models/models_ocr_result_response.py +106 -0
- leapocr-0.0.1/leapocr/generated/leapocr/generated/models/models_ocr_status_response.py +84 -0
- leapocr-0.0.1/leapocr/generated/leapocr/generated/models/models_page_metadata.py +76 -0
- leapocr-0.0.1/leapocr/generated/leapocr/generated/models/models_page_response.py +84 -0
- leapocr-0.0.1/leapocr/generated/leapocr/generated/models/models_pagination_response.py +78 -0
- leapocr-0.0.1/leapocr/generated/leapocr/generated/models/response_error_message.py +72 -0
- leapocr-0.0.1/leapocr/generated/leapocr/generated/models/response_error_response.py +85 -0
- leapocr-0.0.1/leapocr/generated/leapocr/generated/models/status_response.py +88 -0
- leapocr-0.0.1/leapocr/generated/leapocr/generated/models/templates_create_template_request.py +90 -0
- leapocr-0.0.1/leapocr/generated/leapocr/generated/models/templates_list_templates_response.py +88 -0
- leapocr-0.0.1/leapocr/generated/leapocr/generated/models/templates_template_response.py +104 -0
- leapocr-0.0.1/leapocr/generated/leapocr/generated/models/templates_template_stats_response.py +88 -0
- leapocr-0.0.1/leapocr/generated/leapocr/generated/models/templates_update_template_request.py +88 -0
- leapocr-0.0.1/leapocr/generated/leapocr/generated/models/upload_completed_part.py +74 -0
- leapocr-0.0.1/leapocr/generated/leapocr/generated/models/upload_direct_upload_complete_request.py +80 -0
- leapocr-0.0.1/leapocr/generated/leapocr/generated/models/upload_direct_upload_complete_response.py +78 -0
- leapocr-0.0.1/leapocr/generated/leapocr/generated/models/upload_direct_upload_response.py +94 -0
- leapocr-0.0.1/leapocr/generated/leapocr/generated/models/upload_initiate_direct_upload_request.py +96 -0
- leapocr-0.0.1/leapocr/generated/leapocr/generated/models/upload_multipart_part.py +78 -0
- leapocr-0.0.1/leapocr/generated/leapocr/generated/models/upload_remote_url_upload_request.py +94 -0
- leapocr-0.0.1/leapocr/generated/leapocr/generated/models/upload_remote_url_upload_response.py +78 -0
- leapocr-0.0.1/leapocr/generated/leapocr/generated/models/webhooks_r2_upload_notification.py +76 -0
- leapocr-0.0.1/leapocr/generated/leapocr/generated/rest.py +257 -0
- leapocr-0.0.1/leapocr/generated/leapocr/generated_README.md +205 -0
- leapocr-0.0.1/leapocr/models.py +157 -0
- leapocr-0.0.1/leapocr/ocr.py +376 -0
- leapocr-0.0.1/openapi-sdk.json +979 -0
- leapocr-0.0.1/openapi.json +22 -0
- leapocr-0.0.1/openapitools.json +7 -0
- leapocr-0.0.1/pyproject.toml +119 -0
- leapocr-0.0.1/pytest.ini +46 -0
- leapocr-0.0.1/scripts/filter_sdk_endpoints.py +189 -0
- leapocr-0.0.1/tests/__init__.py +1 -0
- leapocr-0.0.1/tests/integration/__init__.py +1 -0
- leapocr-0.0.1/tests/integration/test_ocr.py +322 -0
- leapocr-0.0.1/tests/unit/__init__.py +1 -0
- leapocr-0.0.1/tests/unit/test_errors.py +233 -0
- leapocr-0.0.1/tests/unit/test_models.py +356 -0
- leapocr-0.0.1/tests/unit/test_utils.py +136 -0
- leapocr-0.0.1/tests/unit/test_validation.py +178 -0
- leapocr-0.0.1/uv.lock +673 -0
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
## Description
|
|
2
|
+
|
|
3
|
+
<!-- Provide a brief description of your changes -->
|
|
4
|
+
|
|
5
|
+
## Type of Change
|
|
6
|
+
|
|
7
|
+
<!-- Mark the relevant option with an "x" -->
|
|
8
|
+
|
|
9
|
+
- [ ] Bug fix (non-breaking change which fixes an issue)
|
|
10
|
+
- [ ] New feature (non-breaking change which adds functionality)
|
|
11
|
+
- [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected)
|
|
12
|
+
- [ ] Documentation update
|
|
13
|
+
- [ ] Performance improvement
|
|
14
|
+
- [ ] Code refactoring
|
|
15
|
+
- [ ] Test improvements
|
|
16
|
+
|
|
17
|
+
## Related Issues
|
|
18
|
+
|
|
19
|
+
<!-- Link any related issues here -->
|
|
20
|
+
|
|
21
|
+
Closes #
|
|
22
|
+
|
|
23
|
+
## Changes Made
|
|
24
|
+
|
|
25
|
+
<!-- List the specific changes made in this PR -->
|
|
26
|
+
|
|
27
|
+
-
|
|
28
|
+
-
|
|
29
|
+
-
|
|
30
|
+
|
|
31
|
+
## Testing
|
|
32
|
+
|
|
33
|
+
<!-- Describe the tests you ran to verify your changes -->
|
|
34
|
+
|
|
35
|
+
- [ ] Unit tests pass (`make test`)
|
|
36
|
+
- [ ] Integration tests pass (if applicable)
|
|
37
|
+
- [ ] Added new tests for new functionality
|
|
38
|
+
- [ ] All existing tests still pass
|
|
39
|
+
|
|
40
|
+
## Code Quality
|
|
41
|
+
|
|
42
|
+
<!-- Confirm you've met these requirements -->
|
|
43
|
+
|
|
44
|
+
- [ ] Code follows the project's style guidelines
|
|
45
|
+
- [ ] Ran `make format` to format code
|
|
46
|
+
- [ ] Ran `make lint` and fixed all issues
|
|
47
|
+
- [ ] Ran `make type-check` and fixed all type errors
|
|
48
|
+
- [ ] Added docstrings for new functions/classes
|
|
49
|
+
- [ ] Updated documentation (if needed)
|
|
50
|
+
- [ ] Updated CHANGELOG.md (if applicable)
|
|
51
|
+
|
|
52
|
+
## Additional Context
|
|
53
|
+
|
|
54
|
+
<!-- Add any other context about the PR here -->
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
# PyPI Trusted Publishing Setup
|
|
2
|
+
|
|
3
|
+
This project uses PyPI's trusted publishing feature to securely publish releases without needing API tokens.
|
|
4
|
+
|
|
5
|
+
## Initial Setup (One-Time)
|
|
6
|
+
|
|
7
|
+
### 1. Register the Package on PyPI (if not already registered)
|
|
8
|
+
|
|
9
|
+
If this is the first release:
|
|
10
|
+
|
|
11
|
+
1. Build the package locally:
|
|
12
|
+
```bash
|
|
13
|
+
uv build
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
2. Manually upload the first version using an API token:
|
|
17
|
+
```bash
|
|
18
|
+
# Create a PyPI API token at: https://pypi.org/manage/account/token/
|
|
19
|
+
uv run twine upload dist/*
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
### 2. Configure Trusted Publishing
|
|
23
|
+
|
|
24
|
+
1. Go to https://pypi.org/manage/project/leapocr/settings/publishing/
|
|
25
|
+
|
|
26
|
+
2. Scroll to "Publishing" section
|
|
27
|
+
|
|
28
|
+
3. Click "Add a new pending publisher"
|
|
29
|
+
|
|
30
|
+
4. Fill in the form:
|
|
31
|
+
- **PyPI Project Name**: `leapocr`
|
|
32
|
+
- **Owner**: `leapocr` (GitHub organization/user)
|
|
33
|
+
- **Repository name**: `leapocr-python`
|
|
34
|
+
- **Workflow name**: `release.yml`
|
|
35
|
+
- **Environment name**: `pypi`
|
|
36
|
+
|
|
37
|
+
5. Click "Add"
|
|
38
|
+
|
|
39
|
+
### 3. Create PyPI Environment in GitHub
|
|
40
|
+
|
|
41
|
+
1. Go to https://github.com/leapocr/leapocr-python/settings/environments
|
|
42
|
+
|
|
43
|
+
2. Click "New environment"
|
|
44
|
+
|
|
45
|
+
3. Name it `pypi`
|
|
46
|
+
|
|
47
|
+
4. (Optional) Add protection rules:
|
|
48
|
+
- Required reviewers (for manual approval before publish)
|
|
49
|
+
- Deployment branches (limit to `main` branch only)
|
|
50
|
+
|
|
51
|
+
5. Click "Configure environment"
|
|
52
|
+
|
|
53
|
+
## How It Works
|
|
54
|
+
|
|
55
|
+
1. When you push a tag like `v0.1.0`:
|
|
56
|
+
```bash
|
|
57
|
+
git tag -a v0.1.0 -m "Release v0.1.0"
|
|
58
|
+
git push origin v0.1.0
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
2. GitHub Actions workflow triggers (`release.yml`)
|
|
62
|
+
|
|
63
|
+
3. The workflow:
|
|
64
|
+
- Builds the package
|
|
65
|
+
- Requests a short-lived token from PyPI via OIDC
|
|
66
|
+
- Uses that token to publish to PyPI
|
|
67
|
+
- Creates a GitHub release
|
|
68
|
+
|
|
69
|
+
4. No API tokens needed! ✨
|
|
70
|
+
|
|
71
|
+
## Security Benefits
|
|
72
|
+
|
|
73
|
+
- **No long-lived tokens**: Tokens are generated per-release
|
|
74
|
+
- **Scoped access**: Token only works for this specific project
|
|
75
|
+
- **Audit trail**: All releases tracked in GitHub Actions
|
|
76
|
+
- **Revocable**: Can be disabled/reconfigured at any time
|
|
77
|
+
|
|
78
|
+
## Troubleshooting
|
|
79
|
+
|
|
80
|
+
### Error: "Trusted publisher configuration does not match"
|
|
81
|
+
|
|
82
|
+
This usually means:
|
|
83
|
+
- The repository name is wrong
|
|
84
|
+
- The workflow name doesn't match (`release.yml`)
|
|
85
|
+
- The environment name doesn't match (`pypi`)
|
|
86
|
+
- The tag trigger isn't configured correctly
|
|
87
|
+
|
|
88
|
+
**Solution**: Double-check the PyPI publisher settings match your GitHub repository exactly.
|
|
89
|
+
|
|
90
|
+
### Error: "Insufficient permissions"
|
|
91
|
+
|
|
92
|
+
The workflow needs `id-token: write` permission:
|
|
93
|
+
|
|
94
|
+
```yaml
|
|
95
|
+
permissions:
|
|
96
|
+
contents: read
|
|
97
|
+
id-token: write # Required for trusted publishing
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
This is already configured in `release.yml`.
|
|
101
|
+
|
|
102
|
+
### Error: "Package already exists"
|
|
103
|
+
|
|
104
|
+
If you're trying to upload a version that already exists on PyPI:
|
|
105
|
+
|
|
106
|
+
1. Bump the version in `pyproject.toml`
|
|
107
|
+
2. Create a new tag with the new version
|
|
108
|
+
3. Delete the old tag if needed:
|
|
109
|
+
```bash
|
|
110
|
+
git tag -d v0.1.0
|
|
111
|
+
git push origin :refs/tags/v0.1.0
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
## Testing Releases
|
|
115
|
+
|
|
116
|
+
To test the release process without publishing to PyPI:
|
|
117
|
+
|
|
118
|
+
1. Use TestPyPI for testing:
|
|
119
|
+
- Configure a separate trusted publisher on TestPyPI
|
|
120
|
+
- Create a test workflow that publishes to TestPyPI
|
|
121
|
+
- Test with: `pip install -i https://test.pypi.org/simple/ leapocr`
|
|
122
|
+
|
|
123
|
+
2. Or run the build locally:
|
|
124
|
+
```bash
|
|
125
|
+
make build
|
|
126
|
+
# Check the dist/ folder
|
|
127
|
+
ls -lh dist/
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
## References
|
|
131
|
+
|
|
132
|
+
- [PyPI Trusted Publishing Guide](https://docs.pypi.org/trusted-publishers/)
|
|
133
|
+
- [GitHub Actions OIDC](https://docs.github.com/en/actions/deployment/security-hardening-your-deployments/about-security-hardening-with-openid-connect)
|
|
134
|
+
- [PyPA gh-action-pypi-publish](https://github.com/pypa/gh-action-pypi-publish)
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main, new]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: [main]
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
lint:
|
|
11
|
+
name: Lint and Format Check
|
|
12
|
+
runs-on: ubuntu-latest
|
|
13
|
+
|
|
14
|
+
steps:
|
|
15
|
+
- uses: actions/checkout@v4
|
|
16
|
+
|
|
17
|
+
- name: Set up Python
|
|
18
|
+
uses: actions/setup-python@v5
|
|
19
|
+
with:
|
|
20
|
+
python-version: '3.12'
|
|
21
|
+
|
|
22
|
+
- name: Install uv
|
|
23
|
+
uses: astral-sh/setup-uv@v3
|
|
24
|
+
with:
|
|
25
|
+
enable-cache: true
|
|
26
|
+
|
|
27
|
+
- name: Install dependencies
|
|
28
|
+
run: uv sync
|
|
29
|
+
|
|
30
|
+
- name: Run ruff format check
|
|
31
|
+
run: uv run ruff format --check .
|
|
32
|
+
|
|
33
|
+
- name: Run ruff lint
|
|
34
|
+
run: uv run ruff check .
|
|
35
|
+
|
|
36
|
+
type-check:
|
|
37
|
+
name: Type Check
|
|
38
|
+
runs-on: ubuntu-latest
|
|
39
|
+
|
|
40
|
+
steps:
|
|
41
|
+
- uses: actions/checkout@v4
|
|
42
|
+
|
|
43
|
+
- name: Set up Python
|
|
44
|
+
uses: actions/setup-python@v5
|
|
45
|
+
with:
|
|
46
|
+
python-version: '3.12'
|
|
47
|
+
|
|
48
|
+
- name: Install uv
|
|
49
|
+
uses: astral-sh/setup-uv@v3
|
|
50
|
+
with:
|
|
51
|
+
enable-cache: true
|
|
52
|
+
|
|
53
|
+
- name: Install dependencies
|
|
54
|
+
run: uv sync
|
|
55
|
+
|
|
56
|
+
- name: Run mypy
|
|
57
|
+
run: uv run mypy leapocr/
|
|
58
|
+
|
|
59
|
+
test:
|
|
60
|
+
name: Test Python ${{ matrix.python-version }}
|
|
61
|
+
runs-on: ubuntu-latest
|
|
62
|
+
strategy:
|
|
63
|
+
fail-fast: false
|
|
64
|
+
matrix:
|
|
65
|
+
python-version: ['3.9', '3.10', '3.11', '3.12']
|
|
66
|
+
|
|
67
|
+
steps:
|
|
68
|
+
- uses: actions/checkout@v4
|
|
69
|
+
|
|
70
|
+
- name: Set up Python ${{ matrix.python-version }}
|
|
71
|
+
uses: actions/setup-python@v5
|
|
72
|
+
with:
|
|
73
|
+
python-version: ${{ matrix.python-version }}
|
|
74
|
+
|
|
75
|
+
- name: Install uv
|
|
76
|
+
uses: astral-sh/setup-uv@v3
|
|
77
|
+
with:
|
|
78
|
+
enable-cache: true
|
|
79
|
+
|
|
80
|
+
- name: Install dependencies
|
|
81
|
+
run: uv sync
|
|
82
|
+
|
|
83
|
+
- name: Run unit tests
|
|
84
|
+
run: uv run pytest tests/unit/ -v --tb=short
|
|
85
|
+
|
|
86
|
+
- name: Run tests with coverage
|
|
87
|
+
if: matrix.python-version == '3.12'
|
|
88
|
+
run: |
|
|
89
|
+
uv run pytest tests/unit/ --cov=leapocr --cov-report=xml --cov-report=term
|
|
90
|
+
|
|
91
|
+
- name: Upload coverage to Codecov
|
|
92
|
+
if: matrix.python-version == '3.12'
|
|
93
|
+
uses: codecov/codecov-action@v4
|
|
94
|
+
with:
|
|
95
|
+
file: ./coverage.xml
|
|
96
|
+
fail_ci_if_error: false
|
|
97
|
+
|
|
98
|
+
build:
|
|
99
|
+
name: Build Distribution
|
|
100
|
+
runs-on: ubuntu-latest
|
|
101
|
+
needs: [lint, type-check, test]
|
|
102
|
+
|
|
103
|
+
steps:
|
|
104
|
+
- uses: actions/checkout@v4
|
|
105
|
+
|
|
106
|
+
- name: Set up Python
|
|
107
|
+
uses: actions/setup-python@v5
|
|
108
|
+
with:
|
|
109
|
+
python-version: '3.12'
|
|
110
|
+
|
|
111
|
+
- name: Install uv
|
|
112
|
+
uses: astral-sh/setup-uv@v3
|
|
113
|
+
with:
|
|
114
|
+
enable-cache: true
|
|
115
|
+
|
|
116
|
+
- name: Build package
|
|
117
|
+
run: uv build
|
|
118
|
+
|
|
119
|
+
- name: Verify build artifacts
|
|
120
|
+
run: |
|
|
121
|
+
ls -lh dist/
|
|
122
|
+
python -m pip install dist/*.whl
|
|
123
|
+
python -c "import leapocr; print(f'Installed version: {leapocr.__version__}')"
|
|
124
|
+
|
|
125
|
+
- name: Upload build artifacts
|
|
126
|
+
uses: actions/upload-artifact@v4
|
|
127
|
+
with:
|
|
128
|
+
name: dist
|
|
129
|
+
path: dist/
|
|
130
|
+
retention-days: 30
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
name: Integration Tests
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
workflow_dispatch: # Manual trigger only
|
|
5
|
+
inputs:
|
|
6
|
+
api_base_url:
|
|
7
|
+
description: 'API Base URL'
|
|
8
|
+
required: false
|
|
9
|
+
default: 'http://localhost:8080/api/v1'
|
|
10
|
+
schedule:
|
|
11
|
+
- cron: '0 0 * * 0' # Weekly on Sunday at midnight
|
|
12
|
+
|
|
13
|
+
jobs:
|
|
14
|
+
integration-test:
|
|
15
|
+
name: Integration Tests
|
|
16
|
+
runs-on: ubuntu-latest
|
|
17
|
+
environment: integration-testing
|
|
18
|
+
|
|
19
|
+
steps:
|
|
20
|
+
- uses: actions/checkout@v4
|
|
21
|
+
|
|
22
|
+
- name: Set up Python
|
|
23
|
+
uses: actions/setup-python@v5
|
|
24
|
+
with:
|
|
25
|
+
python-version: '3.12'
|
|
26
|
+
|
|
27
|
+
- name: Install uv
|
|
28
|
+
uses: astral-sh/setup-uv@v3
|
|
29
|
+
with:
|
|
30
|
+
enable-cache: true
|
|
31
|
+
|
|
32
|
+
- name: Install dependencies
|
|
33
|
+
run: uv sync
|
|
34
|
+
|
|
35
|
+
- name: Run integration tests
|
|
36
|
+
env:
|
|
37
|
+
LEAPOCR_API_KEY: ${{ secrets.LEAPOCR_API_KEY }}
|
|
38
|
+
OCR_BASE_URL: ${{ github.event.inputs.api_base_url || 'http://localhost:8080/api/v1' }}
|
|
39
|
+
run: |
|
|
40
|
+
uv run pytest tests/integration/ -v --tb=short -m integration
|
|
41
|
+
|
|
42
|
+
- name: Upload test results
|
|
43
|
+
if: always()
|
|
44
|
+
uses: actions/upload-artifact@v4
|
|
45
|
+
with:
|
|
46
|
+
name: integration-test-results
|
|
47
|
+
path: |
|
|
48
|
+
pytest-report.xml
|
|
49
|
+
pytest-coverage.xml
|
|
50
|
+
retention-days: 30
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
name: Release to PyPI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags:
|
|
6
|
+
- 'v*.*.*'
|
|
7
|
+
|
|
8
|
+
permissions:
|
|
9
|
+
contents: read
|
|
10
|
+
id-token: write # Required for trusted publishing to PyPI
|
|
11
|
+
|
|
12
|
+
jobs:
|
|
13
|
+
build:
|
|
14
|
+
name: Build distribution
|
|
15
|
+
runs-on: ubuntu-latest
|
|
16
|
+
|
|
17
|
+
steps:
|
|
18
|
+
- uses: actions/checkout@v4
|
|
19
|
+
|
|
20
|
+
- name: Set up Python
|
|
21
|
+
uses: actions/setup-python@v5
|
|
22
|
+
with:
|
|
23
|
+
python-version: '3.12'
|
|
24
|
+
|
|
25
|
+
- name: Install uv
|
|
26
|
+
uses: astral-sh/setup-uv@v3
|
|
27
|
+
with:
|
|
28
|
+
enable-cache: true
|
|
29
|
+
|
|
30
|
+
- name: Verify version matches tag
|
|
31
|
+
run: |
|
|
32
|
+
TAG=${GITHUB_REF#refs/tags/v}
|
|
33
|
+
VERSION=$(uv run python -c "import tomllib; print(tomllib.load(open('pyproject.toml', 'rb'))['project']['version'])")
|
|
34
|
+
if [ "$TAG" != "$VERSION" ]; then
|
|
35
|
+
echo "Error: Tag version ($TAG) does not match package version ($VERSION)"
|
|
36
|
+
exit 1
|
|
37
|
+
fi
|
|
38
|
+
echo "Version check passed: $VERSION"
|
|
39
|
+
|
|
40
|
+
- name: Build package
|
|
41
|
+
run: uv build
|
|
42
|
+
|
|
43
|
+
- name: Verify build artifacts
|
|
44
|
+
run: |
|
|
45
|
+
ls -lh dist/
|
|
46
|
+
echo "Build artifacts:"
|
|
47
|
+
echo "$(ls dist/)"
|
|
48
|
+
|
|
49
|
+
- name: Upload artifacts
|
|
50
|
+
uses: actions/upload-artifact@v4
|
|
51
|
+
with:
|
|
52
|
+
name: dist
|
|
53
|
+
path: dist/
|
|
54
|
+
retention-days: 7
|
|
55
|
+
|
|
56
|
+
publish:
|
|
57
|
+
name: Publish to PyPI
|
|
58
|
+
needs: build
|
|
59
|
+
runs-on: ubuntu-latest
|
|
60
|
+
environment:
|
|
61
|
+
name: pypi
|
|
62
|
+
url: https://pypi.org/project/leapocr/
|
|
63
|
+
|
|
64
|
+
steps:
|
|
65
|
+
- name: Download artifacts
|
|
66
|
+
uses: actions/download-artifact@v4
|
|
67
|
+
with:
|
|
68
|
+
name: dist
|
|
69
|
+
path: dist/
|
|
70
|
+
|
|
71
|
+
- name: Publish to PyPI
|
|
72
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
73
|
+
with:
|
|
74
|
+
print-hash: true
|
|
75
|
+
|
|
76
|
+
create-release:
|
|
77
|
+
name: Create GitHub Release
|
|
78
|
+
needs: publish
|
|
79
|
+
runs-on: ubuntu-latest
|
|
80
|
+
permissions:
|
|
81
|
+
contents: write
|
|
82
|
+
|
|
83
|
+
steps:
|
|
84
|
+
- uses: actions/checkout@v4
|
|
85
|
+
|
|
86
|
+
- name: Extract release notes
|
|
87
|
+
id: extract-notes
|
|
88
|
+
run: |
|
|
89
|
+
VERSION=${GITHUB_REF#refs/tags/v}
|
|
90
|
+
echo "version=$VERSION" >> $GITHUB_OUTPUT
|
|
91
|
+
|
|
92
|
+
- name: Create GitHub Release
|
|
93
|
+
uses: softprops/action-gh-release@v2
|
|
94
|
+
with:
|
|
95
|
+
name: Release v${{ steps.extract-notes.outputs.version }}
|
|
96
|
+
body: |
|
|
97
|
+
## Installation
|
|
98
|
+
|
|
99
|
+
```bash
|
|
100
|
+
pip install leapocr==${{ steps.extract-notes.outputs.version }}
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
Or using uv:
|
|
104
|
+
|
|
105
|
+
```bash
|
|
106
|
+
uv add leapocr==${{ steps.extract-notes.outputs.version }}
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
## What's Changed
|
|
110
|
+
|
|
111
|
+
See the [changelog](https://github.com/leapocr/leapocr-python/blob/main/CHANGELOG.md) for details.
|
|
112
|
+
|
|
113
|
+
## Documentation
|
|
114
|
+
|
|
115
|
+
- [Documentation](https://docs.leapocr.com)
|
|
116
|
+
- [Examples](https://github.com/leapocr/leapocr-python/tree/main/examples)
|
|
117
|
+
|
|
118
|
+
---
|
|
119
|
+
|
|
120
|
+
**Full Changelog**: https://github.com/leapocr/leapocr-python/compare/v${{ steps.extract-notes.outputs.version }}...HEAD
|
|
121
|
+
draft: false
|
|
122
|
+
prerelease: false
|
|
123
|
+
generate_release_notes: true
|
leapocr-0.0.1/.gitignore
ADDED
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
# Byte-compiled / optimized / DLL files
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[codz]
|
|
4
|
+
*$py.class
|
|
5
|
+
|
|
6
|
+
# C extensions
|
|
7
|
+
*.so
|
|
8
|
+
|
|
9
|
+
# Distribution / packaging
|
|
10
|
+
.Python
|
|
11
|
+
build/
|
|
12
|
+
develop-eggs/
|
|
13
|
+
dist/
|
|
14
|
+
downloads/
|
|
15
|
+
eggs/
|
|
16
|
+
.eggs/
|
|
17
|
+
lib/
|
|
18
|
+
lib64/
|
|
19
|
+
parts/
|
|
20
|
+
sdist/
|
|
21
|
+
var/
|
|
22
|
+
wheels/
|
|
23
|
+
share/python-wheels/
|
|
24
|
+
*.egg-info/
|
|
25
|
+
.installed.cfg
|
|
26
|
+
*.egg
|
|
27
|
+
MANIFEST
|
|
28
|
+
|
|
29
|
+
# PyInstaller
|
|
30
|
+
# Usually these files are written by a python script from a template
|
|
31
|
+
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
|
32
|
+
*.manifest
|
|
33
|
+
*.spec
|
|
34
|
+
|
|
35
|
+
# Installer logs
|
|
36
|
+
pip-log.txt
|
|
37
|
+
pip-delete-this-directory.txt
|
|
38
|
+
|
|
39
|
+
# Unit test / coverage reports
|
|
40
|
+
htmlcov/
|
|
41
|
+
.tox/
|
|
42
|
+
.nox/
|
|
43
|
+
.coverage
|
|
44
|
+
.coverage.*
|
|
45
|
+
.cache
|
|
46
|
+
nosetests.xml
|
|
47
|
+
coverage.xml
|
|
48
|
+
*.cover
|
|
49
|
+
*.py.cover
|
|
50
|
+
.hypothesis/
|
|
51
|
+
.pytest_cache/
|
|
52
|
+
cover/
|
|
53
|
+
|
|
54
|
+
# Translations
|
|
55
|
+
*.mo
|
|
56
|
+
*.pot
|
|
57
|
+
|
|
58
|
+
# Django stuff:
|
|
59
|
+
*.log
|
|
60
|
+
local_settings.py
|
|
61
|
+
db.sqlite3
|
|
62
|
+
db.sqlite3-journal
|
|
63
|
+
|
|
64
|
+
# Flask stuff:
|
|
65
|
+
instance/
|
|
66
|
+
.webassets-cache
|
|
67
|
+
|
|
68
|
+
# Scrapy stuff:
|
|
69
|
+
.scrapy
|
|
70
|
+
|
|
71
|
+
# Sphinx documentation
|
|
72
|
+
docs/_build/
|
|
73
|
+
|
|
74
|
+
# PyBuilder
|
|
75
|
+
.pybuilder/
|
|
76
|
+
target/
|
|
77
|
+
|
|
78
|
+
# Jupyter Notebook
|
|
79
|
+
.ipynb_checkpoints
|
|
80
|
+
|
|
81
|
+
# IPython
|
|
82
|
+
profile_default/
|
|
83
|
+
ipython_config.py
|
|
84
|
+
|
|
85
|
+
# pyenv
|
|
86
|
+
# For a library or package, you might want to ignore these files since the code is
|
|
87
|
+
# intended to run in multiple environments; otherwise, check them in:
|
|
88
|
+
# .python-version
|
|
89
|
+
|
|
90
|
+
# pipenv
|
|
91
|
+
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
|
92
|
+
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
|
93
|
+
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
|
94
|
+
# install all needed dependencies.
|
|
95
|
+
# Pipfile.lock
|
|
96
|
+
|
|
97
|
+
# UV
|
|
98
|
+
# Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control.
|
|
99
|
+
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
|
100
|
+
# commonly ignored for libraries.
|
|
101
|
+
# uv.lock
|
|
102
|
+
|
|
103
|
+
# poetry
|
|
104
|
+
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
|
|
105
|
+
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
|
106
|
+
# commonly ignored for libraries.
|
|
107
|
+
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
|
|
108
|
+
# poetry.lock
|
|
109
|
+
# poetry.toml
|
|
110
|
+
|
|
111
|
+
# pdm
|
|
112
|
+
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
|
|
113
|
+
# pdm recommends including project-wide configuration in pdm.toml, but excluding .pdm-python.
|
|
114
|
+
# https://pdm-project.org/en/latest/usage/project/#working-with-version-control
|
|
115
|
+
# pdm.lock
|
|
116
|
+
# pdm.toml
|
|
117
|
+
.pdm-python
|
|
118
|
+
.pdm-build/
|
|
119
|
+
|
|
120
|
+
# pixi
|
|
121
|
+
# Similar to Pipfile.lock, it is generally recommended to include pixi.lock in version control.
|
|
122
|
+
# pixi.lock
|
|
123
|
+
# Pixi creates a virtual environment in the .pixi directory, just like venv module creates one
|
|
124
|
+
# in the .venv directory. It is recommended not to include this directory in version control.
|
|
125
|
+
.pixi
|
|
126
|
+
|
|
127
|
+
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
|
|
128
|
+
__pypackages__/
|
|
129
|
+
|
|
130
|
+
# Celery stuff
|
|
131
|
+
celerybeat-schedule
|
|
132
|
+
celerybeat.pid
|
|
133
|
+
|
|
134
|
+
# Redis
|
|
135
|
+
*.rdb
|
|
136
|
+
*.aof
|
|
137
|
+
*.pid
|
|
138
|
+
|
|
139
|
+
# RabbitMQ
|
|
140
|
+
mnesia/
|
|
141
|
+
rabbitmq/
|
|
142
|
+
rabbitmq-data/
|
|
143
|
+
|
|
144
|
+
# ActiveMQ
|
|
145
|
+
activemq-data/
|
|
146
|
+
|
|
147
|
+
# SageMath parsed files
|
|
148
|
+
*.sage.py
|
|
149
|
+
|
|
150
|
+
# Environments
|
|
151
|
+
.env
|
|
152
|
+
.envrc
|
|
153
|
+
.venv
|
|
154
|
+
env/
|
|
155
|
+
venv/
|
|
156
|
+
ENV/
|
|
157
|
+
env.bak/
|
|
158
|
+
venv.bak/
|
|
159
|
+
|
|
160
|
+
# Spyder project settings
|
|
161
|
+
.spyderproject
|
|
162
|
+
.spyproject
|
|
163
|
+
|
|
164
|
+
# Rope project settings
|
|
165
|
+
.ropeproject
|
|
166
|
+
|
|
167
|
+
# mkdocs documentation
|
|
168
|
+
/site
|
|
169
|
+
|
|
170
|
+
# mypy
|
|
171
|
+
.mypy_cache/
|
|
172
|
+
.dmypy.json
|
|
173
|
+
dmypy.json
|
|
174
|
+
|
|
175
|
+
# Pyre type checker
|
|
176
|
+
.pyre/
|
|
177
|
+
|
|
178
|
+
# pytype static type analyzer
|
|
179
|
+
.pytype/
|
|
180
|
+
|
|
181
|
+
# Cython debug symbols
|
|
182
|
+
cython_debug/
|
|
183
|
+
|
|
184
|
+
# PyCharm
|
|
185
|
+
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
|
|
186
|
+
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
|
|
187
|
+
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
|
188
|
+
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
|
189
|
+
# .idea/
|
|
190
|
+
|
|
191
|
+
# Abstra
|
|
192
|
+
# Abstra is an AI-powered process automation framework.
|
|
193
|
+
# Ignore directories containing user credentials, local state, and settings.
|
|
194
|
+
# Learn more at https://abstra.io/docs
|
|
195
|
+
.abstra/
|
|
196
|
+
|
|
197
|
+
# Visual Studio Code
|
|
198
|
+
# Visual Studio Code specific template is maintained in a separate VisualStudioCode.gitignore
|
|
199
|
+
# that can be found at https://github.com/github/gitignore/blob/main/Global/VisualStudioCode.gitignore
|
|
200
|
+
# and can be added to the global gitignore or merged into this file. However, if you prefer,
|
|
201
|
+
# you could uncomment the following to ignore the entire vscode folder
|
|
202
|
+
# .vscode/
|
|
203
|
+
|
|
204
|
+
# Ruff stuff:
|
|
205
|
+
.ruff_cache/
|
|
206
|
+
|
|
207
|
+
# PyPI configuration file
|
|
208
|
+
.pypirc
|
|
209
|
+
|
|
210
|
+
# Marimo
|
|
211
|
+
marimo/_static/
|
|
212
|
+
marimo/_lsp/
|
|
213
|
+
__marimo__/
|
|
214
|
+
|
|
215
|
+
# Streamlit
|
|
216
|
+
.streamlit/secrets.toml
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
3.12
|