textverified 0.1.0a0__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.
- textverified-0.1.0a0/.github/workflows/pr-tests.yml +248 -0
- textverified-0.1.0a0/.github/workflows/python-publish.yml +160 -0
- textverified-0.1.0a0/.gitignore +50 -0
- textverified-0.1.0a0/.vscode/settings.json +25 -0
- textverified-0.1.0a0/LICENSE +21 -0
- textverified-0.1.0a0/PKG-INFO +268 -0
- textverified-0.1.0a0/README.md +231 -0
- textverified-0.1.0a0/docs/api_reference.rst +85 -0
- textverified-0.1.0a0/docs/conf.py +96 -0
- textverified-0.1.0a0/docs/examples.rst +262 -0
- textverified-0.1.0a0/docs/index.rst +44 -0
- textverified-0.1.0a0/docs/quickstart.rst +182 -0
- textverified-0.1.0a0/generate_enums.py +674 -0
- textverified-0.1.0a0/pyproject.toml +62 -0
- textverified-0.1.0a0/questions.txt +19 -0
- textverified-0.1.0a0/setup.cfg +4 -0
- textverified-0.1.0a0/setup.py +36 -0
- textverified-0.1.0a0/swagger.json +3739 -0
- textverified-0.1.0a0/tests/__init__.py +0 -0
- textverified-0.1.0a0/tests/fixtures.py +367 -0
- textverified-0.1.0a0/tests/mock_endpoints/api.pub.v2.auth.json +9 -0
- textverified-0.1.0a0/tests/mock_endpoints/api.pub.v2.fake-endpoint.json +7 -0
- textverified-0.1.0a0/tests/mock_endpoints/api.pub.v2.list.page1.json +14 -0
- textverified-0.1.0a0/tests/mock_endpoints/api.pub.v2.list.page2.json +17 -0
- textverified-0.1.0a0/tests/mock_endpoints_generated/api.pub.v2.account.me.json +8 -0
- textverified-0.1.0a0/tests/mock_endpoints_generated/api.pub.v2.area-codes.json +14 -0
- textverified-0.1.0a0/tests/mock_endpoints_generated/api.pub.v2.auth.json +13 -0
- textverified-0.1.0a0/tests/mock_endpoints_generated/api.pub.v2.backorders.{id}.json +18 -0
- textverified-0.1.0a0/tests/mock_endpoints_generated/api.pub.v2.billing-cycles.json +29 -0
- textverified-0.1.0a0/tests/mock_endpoints_generated/api.pub.v2.billing-cycles.{id}.invoices.json +344 -0
- textverified-0.1.0a0/tests/mock_endpoints_generated/api.pub.v2.billing-cycles.{id}.json +25 -0
- textverified-0.1.0a0/tests/mock_endpoints_generated/api.pub.v2.billing-cycles.{id}.next-invoice.json +172 -0
- textverified-0.1.0a0/tests/mock_endpoints_generated/api.pub.v2.billing-cycles.{id}.renew.json +169 -0
- textverified-0.1.0a0/tests/mock_endpoints_generated/api.pub.v2.legacy.reservation-id-lookup.json +8 -0
- textverified-0.1.0a0/tests/mock_endpoints_generated/api.pub.v2.pricing.rentals.json +8 -0
- textverified-0.1.0a0/tests/mock_endpoints_generated/api.pub.v2.pricing.verifications.json +8 -0
- textverified-0.1.0a0/tests/mock_endpoints_generated/api.pub.v2.reservations.rental.json +8 -0
- textverified-0.1.0a0/tests/mock_endpoints_generated/api.pub.v2.reservations.rental.nonrenewable.json +43 -0
- textverified-0.1.0a0/tests/mock_endpoints_generated/api.pub.v2.reservations.rental.nonrenewable.{id}.json +35 -0
- textverified-0.1.0a0/tests/mock_endpoints_generated/api.pub.v2.reservations.rental.nonrenewable.{id}.refund.json +8 -0
- textverified-0.1.0a0/tests/mock_endpoints_generated/api.pub.v2.reservations.rental.renewable.json +50 -0
- textverified-0.1.0a0/tests/mock_endpoints_generated/api.pub.v2.reservations.rental.renewable.{id}.json +36 -0
- textverified-0.1.0a0/tests/mock_endpoints_generated/api.pub.v2.reservations.rental.renewable.{id}.refund.json +8 -0
- textverified-0.1.0a0/tests/mock_endpoints_generated/api.pub.v2.reservations.rental.renewable.{id}.renew.json +8 -0
- textverified-0.1.0a0/tests/mock_endpoints_generated/api.pub.v2.reservations.rentals.extensions.json +5 -0
- textverified-0.1.0a0/tests/mock_endpoints_generated/api.pub.v2.reservations.{id}.health.json +11 -0
- textverified-0.1.0a0/tests/mock_endpoints_generated/api.pub.v2.reservations.{id}.json +14 -0
- textverified-0.1.0a0/tests/mock_endpoints_generated/api.pub.v2.sales.json +39 -0
- textverified-0.1.0a0/tests/mock_endpoints_generated/api.pub.v2.sales.{id}.json +54 -0
- textverified-0.1.0a0/tests/mock_endpoints_generated/api.pub.v2.services.json +18 -0
- textverified-0.1.0a0/tests/mock_endpoints_generated/api.pub.v2.sms.json +40 -0
- textverified-0.1.0a0/tests/mock_endpoints_generated/api.pub.v2.verifications.json +47 -0
- textverified-0.1.0a0/tests/mock_endpoints_generated/api.pub.v2.verifications.{id}.cancel.json +8 -0
- textverified-0.1.0a0/tests/mock_endpoints_generated/api.pub.v2.verifications.{id}.json +48 -0
- textverified-0.1.0a0/tests/mock_endpoints_generated/api.pub.v2.verifications.{id}.reactivate.json +11 -0
- textverified-0.1.0a0/tests/mock_endpoints_generated/api.pub.v2.verifications.{id}.report.json +8 -0
- textverified-0.1.0a0/tests/mock_endpoints_generated/api.pub.v2.verifications.{id}.reuse.json +11 -0
- textverified-0.1.0a0/tests/mock_endpoints_generated/api.pub.v2.wake-requests.estimate.json +9 -0
- textverified-0.1.0a0/tests/mock_endpoints_generated/api.pub.v2.wake-requests.json +8 -0
- textverified-0.1.0a0/tests/mock_endpoints_generated/api.pub.v2.wake-requests.{id}.json +14 -0
- textverified-0.1.0a0/tests/mock_endpoints_generated/api.pub.v2.webhook-events.json +5 -0
- textverified-0.1.0a0/tests/test_accounts.py +29 -0
- textverified-0.1.0a0/tests/test_billing_cycles.py +108 -0
- textverified-0.1.0a0/tests/test_paginated_list.py +71 -0
- textverified-0.1.0a0/tests/test_reservations.py +244 -0
- textverified-0.1.0a0/tests/test_sales.py +25 -0
- textverified-0.1.0a0/tests/test_services.py +28 -0
- textverified-0.1.0a0/tests/test_sms.py +162 -0
- textverified-0.1.0a0/tests/test_textverified.py +111 -0
- textverified-0.1.0a0/tests/test_verifications.py +152 -0
- textverified-0.1.0a0/tests/test_wake_requests.py +325 -0
- textverified-0.1.0a0/textverified/__init__.py +288 -0
- textverified-0.1.0a0/textverified/account_api.py +32 -0
- textverified-0.1.0a0/textverified/action.py +47 -0
- textverified-0.1.0a0/textverified/billing_cycle_api.py +178 -0
- textverified-0.1.0a0/textverified/data/__init__.py +9 -0
- textverified-0.1.0a0/textverified/data/dtypes.py +1561 -0
- textverified-0.1.0a0/textverified/exceptions.py +13 -0
- textverified-0.1.0a0/textverified/paginated_list.py +111 -0
- textverified-0.1.0a0/textverified/reservations_api.py +669 -0
- textverified-0.1.0a0/textverified/sales_api.py +52 -0
- textverified-0.1.0a0/textverified/services_api.py +48 -0
- textverified-0.1.0a0/textverified/sms_api.py +191 -0
- textverified-0.1.0a0/textverified/textverified.py +167 -0
- textverified-0.1.0a0/textverified/verifications_api.py +338 -0
- textverified-0.1.0a0/textverified/wake_api.py +218 -0
- textverified-0.1.0a0/textverified.egg-info/PKG-INFO +268 -0
- textverified-0.1.0a0/textverified.egg-info/SOURCES.txt +89 -0
- textverified-0.1.0a0/textverified.egg-info/dependency_links.txt +1 -0
- textverified-0.1.0a0/textverified.egg-info/requires.txt +15 -0
- textverified-0.1.0a0/textverified.egg-info/top_level.txt +1 -0
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
# This workflow runs tests and checks on pull requests
|
|
2
|
+
# oh also this is completely untested
|
|
3
|
+
name: PR Tests & Quality Checks
|
|
4
|
+
|
|
5
|
+
on:
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: [ master, main ]
|
|
8
|
+
types: [opened, synchronize, reopened]
|
|
9
|
+
|
|
10
|
+
jobs:
|
|
11
|
+
workflow-info:
|
|
12
|
+
name: Post Workflow Info
|
|
13
|
+
runs-on: ubuntu-latest
|
|
14
|
+
|
|
15
|
+
steps:
|
|
16
|
+
- name: Minimize previous workflow comments and post new info
|
|
17
|
+
uses: actions/github-script@v6
|
|
18
|
+
with:
|
|
19
|
+
script: |
|
|
20
|
+
const workflowUrl = `${context.payload.repository.html_url}/actions/runs/${context.runId}`;
|
|
21
|
+
const rerunUrl = `${context.payload.repository.html_url}/actions/runs/${context.runId}`;
|
|
22
|
+
|
|
23
|
+
// First, minimize previous workflow comments from this bot
|
|
24
|
+
try {
|
|
25
|
+
const comments = await github.rest.issues.listComments({
|
|
26
|
+
owner: context.repo.owner,
|
|
27
|
+
repo: context.repo.repo,
|
|
28
|
+
issue_number: context.issue.number
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
const botComments = comments.data.filter(comment =>
|
|
32
|
+
comment.user.type === 'Bot' &&
|
|
33
|
+
(comment.body.includes('🚀 PR Quality Checks') ||
|
|
34
|
+
comment.body.includes('🧪 Tests & Coverage') ||
|
|
35
|
+
comment.body.includes('🎨 Black Formatting'))
|
|
36
|
+
);
|
|
37
|
+
|
|
38
|
+
// delete previous comments
|
|
39
|
+
for (const comment of botComments) {
|
|
40
|
+
await github.rest.issues.deleteComment({
|
|
41
|
+
owner: context.repo.owner,
|
|
42
|
+
repo: context.repo.repo,
|
|
43
|
+
comment_id: comment.id
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
} catch (error) {
|
|
48
|
+
console.log('Could not minimize previous comments:', error.message);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// Now post the new workflow info
|
|
52
|
+
const comment = `## 🚀 PR Quality Checks Started
|
|
53
|
+
|
|
54
|
+
**Workflow:** [View Details](${workflowUrl})
|
|
55
|
+
|
|
56
|
+
The following checks are running:
|
|
57
|
+
- 🧪 **Tests & Coverage** - Running test suite and analyzing coverage
|
|
58
|
+
- 🎨 **Black Formatting** - Checking code formatting compliance
|
|
59
|
+
|
|
60
|
+
<details>
|
|
61
|
+
<summary>🔄 Rerun Checks</summary>
|
|
62
|
+
|
|
63
|
+
If you need to rerun the checks, you can:
|
|
64
|
+
1. [Rerun this workflow](${rerunUrl}) (requires write access)
|
|
65
|
+
2. Push a new commit to trigger checks again
|
|
66
|
+
3. Close and reopen this PR
|
|
67
|
+
|
|
68
|
+
</details>
|
|
69
|
+
|
|
70
|
+
---
|
|
71
|
+
*Results will be posted as separate comments when each check completes.*`;
|
|
72
|
+
|
|
73
|
+
github.rest.issues.createComment({
|
|
74
|
+
issue_number: context.issue.number,
|
|
75
|
+
owner: context.repo.owner,
|
|
76
|
+
repo: context.repo.repo,
|
|
77
|
+
body: comment
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
tests-and-coverage:
|
|
81
|
+
name: Run Tests and Coverage
|
|
82
|
+
runs-on: ubuntu-latest
|
|
83
|
+
|
|
84
|
+
steps:
|
|
85
|
+
- name: Checkout PR code
|
|
86
|
+
uses: actions/checkout@v4
|
|
87
|
+
with:
|
|
88
|
+
ref: ${{ github.event.pull_request.head.sha }}
|
|
89
|
+
|
|
90
|
+
- name: Set up Python
|
|
91
|
+
uses: actions/setup-python@v4
|
|
92
|
+
with:
|
|
93
|
+
python-version: '3.11'
|
|
94
|
+
|
|
95
|
+
- name: Install dependencies
|
|
96
|
+
run: |
|
|
97
|
+
python -m pip install --upgrade pip
|
|
98
|
+
python setup.py develop
|
|
99
|
+
pip install .[dev]
|
|
100
|
+
|
|
101
|
+
- name: Run tests with coverage
|
|
102
|
+
id: test-coverage
|
|
103
|
+
run: |
|
|
104
|
+
echo "## Tests & Coverage Results 🧪📊" >> $GITHUB_STEP_SUMMARY
|
|
105
|
+
pytest --verbose --cov=textverified --cov-report=xml --cov-report=term 2>&1 | tee test-coverage-output.txt
|
|
106
|
+
exit_code=${PIPESTATUS[0]}
|
|
107
|
+
|
|
108
|
+
if [ $exit_code -eq 0 ]; then
|
|
109
|
+
echo "✅ All tests passed!" >> $GITHUB_STEP_SUMMARY
|
|
110
|
+
else
|
|
111
|
+
echo "❌ Some tests failed" >> $GITHUB_STEP_SUMMARY
|
|
112
|
+
echo "" >> $GITHUB_STEP_SUMMARY
|
|
113
|
+
echo "### Failed Tests:" >> $GITHUB_STEP_SUMMARY
|
|
114
|
+
echo "\`\`\`" >> $GITHUB_STEP_SUMMARY
|
|
115
|
+
grep -A 5 -B 2 "FAILED\|ERROR" test-coverage-output.txt || echo "Check full output for details" >> $GITHUB_STEP_SUMMARY
|
|
116
|
+
echo "\`\`\`" >> $GITHUB_STEP_SUMMARY
|
|
117
|
+
fi
|
|
118
|
+
|
|
119
|
+
echo "" >> $GITHUB_STEP_SUMMARY
|
|
120
|
+
echo "### Coverage Report:" >> $GITHUB_STEP_SUMMARY
|
|
121
|
+
echo "\`\`\`" >> $GITHUB_STEP_SUMMARY
|
|
122
|
+
grep -A 20 "coverage report" test-coverage-output.txt || echo "Coverage report generated" >> $GITHUB_STEP_SUMMARY
|
|
123
|
+
echo "\`\`\`" >> $GITHUB_STEP_SUMMARY
|
|
124
|
+
|
|
125
|
+
exit $exit_code
|
|
126
|
+
|
|
127
|
+
- name: Comment PR with test and coverage results
|
|
128
|
+
if: always()
|
|
129
|
+
uses: actions/github-script@v6
|
|
130
|
+
with:
|
|
131
|
+
script: |
|
|
132
|
+
const fs = require('fs');
|
|
133
|
+
let comment = '## 🧪 Tests & Coverage Results\n\n';
|
|
134
|
+
|
|
135
|
+
try {
|
|
136
|
+
const output = fs.readFileSync('test-coverage-output.txt', 'utf8');
|
|
137
|
+
const lines = output.split('\n');
|
|
138
|
+
|
|
139
|
+
// Test results section
|
|
140
|
+
const testSummary = lines.filter(line =>
|
|
141
|
+
/\s+failed/i.test(line) ||
|
|
142
|
+
/\s+error/i.test(line) ||
|
|
143
|
+
/\s+FAILED/i.test(line) ||
|
|
144
|
+
/\s+ERROR/i.test(line)
|
|
145
|
+
)
|
|
146
|
+
|
|
147
|
+
if (testSummary.length > 0) {
|
|
148
|
+
comment += '### 🧪 Test Results\n```\n' + testSummary.join('\n') + '\n```\n\n';
|
|
149
|
+
} else {
|
|
150
|
+
comment += '### 🧪 Test Results\n✅ All tests passed!\n\n';
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// Coverage section
|
|
154
|
+
const coverageStart = lines.findIndex(line => line.includes('coverage: platform'));
|
|
155
|
+
const coverageLines = lines.slice(coverageStart + 1, lines.length - 1);
|
|
156
|
+
|
|
157
|
+
if (coverageLines.length > 0) {
|
|
158
|
+
comment += '### 📊 Coverage Report\n```\n' + coverageLines.join('\n') + '\n```\n';
|
|
159
|
+
} else {
|
|
160
|
+
comment += '### 📊 Coverage Report\nCoverage report generated. Check artifacts for details.\n';
|
|
161
|
+
}
|
|
162
|
+
} catch (error) {
|
|
163
|
+
comment += 'Could not read test/coverage output.\n';
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
github.rest.issues.createComment({
|
|
167
|
+
issue_number: context.issue.number,
|
|
168
|
+
owner: context.repo.owner,
|
|
169
|
+
repo: context.repo.repo,
|
|
170
|
+
body: comment
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
black-formatting:
|
|
174
|
+
name: Check Black formatting
|
|
175
|
+
runs-on: ubuntu-latest
|
|
176
|
+
|
|
177
|
+
steps:
|
|
178
|
+
- name: Checkout PR code
|
|
179
|
+
uses: actions/checkout@v4
|
|
180
|
+
with:
|
|
181
|
+
ref: ${{ github.event.pull_request.head.sha }}
|
|
182
|
+
|
|
183
|
+
- name: Set up Python
|
|
184
|
+
uses: actions/setup-python@v4
|
|
185
|
+
with:
|
|
186
|
+
python-version: '3.11'
|
|
187
|
+
|
|
188
|
+
- name: Install dependencies
|
|
189
|
+
run: |
|
|
190
|
+
python -m pip install --upgrade pip
|
|
191
|
+
python setup.py develop
|
|
192
|
+
pip install .[dev]
|
|
193
|
+
|
|
194
|
+
- name: Check Black formatting
|
|
195
|
+
id: black-check
|
|
196
|
+
run: |
|
|
197
|
+
echo "## Black Formatting Check 🎨" >> $GITHUB_STEP_SUMMARY
|
|
198
|
+
|
|
199
|
+
# Run black in check mode to see if files need formatting
|
|
200
|
+
if black --check --diff . > black-diff.txt 2>&1; then
|
|
201
|
+
echo "✅ All files are properly formatted!" >> $GITHUB_STEP_SUMMARY
|
|
202
|
+
echo "FORMATTING_OK=true" >> $GITHUB_ENV
|
|
203
|
+
else
|
|
204
|
+
echo "❌ Some files need formatting" >> $GITHUB_STEP_SUMMARY
|
|
205
|
+
echo "FORMATTING_OK=false" >> $GITHUB_ENV
|
|
206
|
+
echo "" >> $GITHUB_STEP_SUMMARY
|
|
207
|
+
echo "### Files that need formatting:" >> $GITHUB_STEP_SUMMARY
|
|
208
|
+
echo "\`\`\`diff" >> $GITHUB_STEP_SUMMARY
|
|
209
|
+
head -50 black-diff.txt >> $GITHUB_STEP_SUMMARY
|
|
210
|
+
echo "\`\`\`" >> $GITHUB_STEP_SUMMARY
|
|
211
|
+
fi
|
|
212
|
+
continue-on-error: true
|
|
213
|
+
|
|
214
|
+
- name: Comment PR with formatting results
|
|
215
|
+
uses: actions/github-script@v6
|
|
216
|
+
with:
|
|
217
|
+
script: |
|
|
218
|
+
const fs = require('fs');
|
|
219
|
+
let comment = '## 🎨 Black Formatting Check\n\n';
|
|
220
|
+
|
|
221
|
+
if (process.env.FORMATTING_OK === 'true') {
|
|
222
|
+
comment += '✅ All files are properly formatted!\n\n';
|
|
223
|
+
} else {
|
|
224
|
+
comment += '❌ Some files need formatting. Here are the differences:\n\n';
|
|
225
|
+
|
|
226
|
+
try {
|
|
227
|
+
const diff = fs.readFileSync('black-diff.txt', 'utf8');
|
|
228
|
+
if (diff.trim()) {
|
|
229
|
+
comment += '```diff\n' + diff.substring(0, 3000) + '\n```\n\n';
|
|
230
|
+
if (diff.length > 3000) {
|
|
231
|
+
comment += '*Note: Diff truncated. Run `black .` locally to see all changes.*\n\n';
|
|
232
|
+
}
|
|
233
|
+
} else {
|
|
234
|
+
comment += 'Run `black .` to format your code.\n\n';
|
|
235
|
+
}
|
|
236
|
+
} catch (error) {
|
|
237
|
+
comment += 'Could not read formatting diff.\n\n';
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
comment += '**To fix:** Run `black .` in your local repository.\n';
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
github.rest.issues.createComment({
|
|
244
|
+
issue_number: context.issue.number,
|
|
245
|
+
owner: context.repo.owner,
|
|
246
|
+
repo: context.repo.repo,
|
|
247
|
+
body: comment
|
|
248
|
+
});
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
# Create new release and publish Python package to PyPI and GitHub Releases
|
|
2
|
+
# https://help.github.com/en/actions/language-and-framework-guides/using-python-with-github-actions#publishing-to-package-registries
|
|
3
|
+
# oh also this is completely untested
|
|
4
|
+
|
|
5
|
+
name: Build & Publish
|
|
6
|
+
|
|
7
|
+
on:
|
|
8
|
+
workflow_dispatch:
|
|
9
|
+
inputs:
|
|
10
|
+
release_notes:
|
|
11
|
+
description: 'Release notes for the new version'
|
|
12
|
+
required: true
|
|
13
|
+
|
|
14
|
+
jobs:
|
|
15
|
+
build-release:
|
|
16
|
+
|
|
17
|
+
runs-on: ubuntu-latest
|
|
18
|
+
strategy:
|
|
19
|
+
matrix:
|
|
20
|
+
python-version: ['3.7.1', '3.8.0', '3.9.0', '3.10.0', '3.11.0', '3.12.0', '3.13.0']
|
|
21
|
+
|
|
22
|
+
steps:
|
|
23
|
+
|
|
24
|
+
- uses: actions/checkout@v2
|
|
25
|
+
|
|
26
|
+
- name: Extract Python major.minor version
|
|
27
|
+
id: python-version
|
|
28
|
+
run: |
|
|
29
|
+
VERSION="${{ matrix.python-version }}"
|
|
30
|
+
MAJOR_MINOR=$(echo $VERSION | cut -d. -f1,2)
|
|
31
|
+
echo "major_minor=$MAJOR_MINOR" >> $GITHUB_OUTPUT
|
|
32
|
+
echo "python_cmd=python$MAJOR_MINOR" >> $GITHUB_OUTPUT
|
|
33
|
+
echo "Need Python $MAJOR_MINOR (from $VERSION)"
|
|
34
|
+
|
|
35
|
+
- name: Try standard Python setup first
|
|
36
|
+
id: standard-setup
|
|
37
|
+
continue-on-error: true
|
|
38
|
+
uses: actions/setup-python@v2
|
|
39
|
+
with:
|
|
40
|
+
python-version: ${{ matrix.python-version }}
|
|
41
|
+
|
|
42
|
+
- name: Install Python from deadsnakes PPA (fallback)
|
|
43
|
+
if: steps.standard-setup.outcome == 'failure'
|
|
44
|
+
run: |
|
|
45
|
+
echo "Standard setup failed, trying deadsnakes PPA..."
|
|
46
|
+
sudo add-apt-repository ppa:deadsnakes/ppa -y
|
|
47
|
+
sudo apt-get update
|
|
48
|
+
|
|
49
|
+
PYTHON_CMD="${{ steps.python-version.outputs.python_cmd }}"
|
|
50
|
+
MAJOR_MINOR="${{ steps.python-version.outputs.major_minor }}"
|
|
51
|
+
|
|
52
|
+
# Install Python and essential packages
|
|
53
|
+
sudo apt-get install -y \
|
|
54
|
+
$PYTHON_CMD \
|
|
55
|
+
$PYTHON_CMD-dev \
|
|
56
|
+
$PYTHON_CMD-distutils \
|
|
57
|
+
$PYTHON_CMD-venv
|
|
58
|
+
|
|
59
|
+
# Create a virtual environment to avoid system package conflicts
|
|
60
|
+
$PYTHON_CMD -m venv /tmp/python-env
|
|
61
|
+
source /tmp/python-env/bin/activate
|
|
62
|
+
|
|
63
|
+
# The virtual environment comes with a clean pip
|
|
64
|
+
python -m pip install --upgrade pip setuptools wheel
|
|
65
|
+
|
|
66
|
+
echo "Successfully installed $PYTHON_CMD from deadsnakes with virtual environment"
|
|
67
|
+
|
|
68
|
+
- name: Set Python environment variables
|
|
69
|
+
run: |
|
|
70
|
+
if [[ "${{ steps.standard-setup.outcome }}" == "failure" ]]; then
|
|
71
|
+
# Use deadsnakes installation with virtual environment
|
|
72
|
+
echo "VIRTUAL_ENV=/tmp/python-env" >> $GITHUB_ENV
|
|
73
|
+
echo "PATH=/tmp/python-env/bin:$PATH" >> $GITHUB_ENV
|
|
74
|
+
echo "PYTHON=/tmp/python-env/bin/python" >> $GITHUB_ENV
|
|
75
|
+
echo "PIP=/tmp/python-env/bin/pip" >> $GITHUB_ENV
|
|
76
|
+
echo "Using deadsnakes Python with virtual environment"
|
|
77
|
+
else
|
|
78
|
+
# Use standard installation
|
|
79
|
+
echo "PYTHON=python" >> $GITHUB_ENV
|
|
80
|
+
echo "PIP=python -m pip" >> $GITHUB_ENV
|
|
81
|
+
echo "Using standard Python setup"
|
|
82
|
+
fi
|
|
83
|
+
|
|
84
|
+
- name: Install dependencies
|
|
85
|
+
run: |
|
|
86
|
+
$PIP install setuptools wheel tomli
|
|
87
|
+
$PIP install -e "."
|
|
88
|
+
|
|
89
|
+
- name: Build Release
|
|
90
|
+
run: |
|
|
91
|
+
$PYTHON setup.py sdist bdist_wheel
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
load-pkg-version:
|
|
95
|
+
runs-on: ubuntu-latest
|
|
96
|
+
outputs:
|
|
97
|
+
version: ${{ steps.get-version.outputs.version }}
|
|
98
|
+
|
|
99
|
+
steps:
|
|
100
|
+
- uses: actions/checkout@v2
|
|
101
|
+
|
|
102
|
+
- name: Set up Python
|
|
103
|
+
uses: actions/setup-python@v2
|
|
104
|
+
with:
|
|
105
|
+
python-version: '3.11'
|
|
106
|
+
|
|
107
|
+
- name: Install toml
|
|
108
|
+
run: pip install toml
|
|
109
|
+
|
|
110
|
+
- name: Get Version from pyproject.toml
|
|
111
|
+
id: get-version
|
|
112
|
+
run: |
|
|
113
|
+
python -c "
|
|
114
|
+
import toml
|
|
115
|
+
pyproject = toml.load('pyproject.toml')
|
|
116
|
+
version = pyproject['project']['version']
|
|
117
|
+
print(f'version={version}')
|
|
118
|
+
" >> $GITHUB_OUTPUT
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
release-pypi:
|
|
122
|
+
needs: build-release
|
|
123
|
+
runs-on: ubuntu-latest
|
|
124
|
+
|
|
125
|
+
steps:
|
|
126
|
+
- uses: actions/checkout@v2
|
|
127
|
+
|
|
128
|
+
- name: Install Twine
|
|
129
|
+
run: |
|
|
130
|
+
python -m pip install --upgrade pip
|
|
131
|
+
pip install twine
|
|
132
|
+
|
|
133
|
+
- name: Publish to PyPI
|
|
134
|
+
env:
|
|
135
|
+
TWINE_USERNAME: ${{ secrets.PYPI_USERNAME }}
|
|
136
|
+
TWINE_PASSWORD: ${{ secrets.PYPI_PASSWORD }}
|
|
137
|
+
run: |
|
|
138
|
+
twine upload dist/*
|
|
139
|
+
|
|
140
|
+
release-github:
|
|
141
|
+
needs: [build-release, load-pkg-version]
|
|
142
|
+
runs-on: ubuntu-latest
|
|
143
|
+
|
|
144
|
+
steps:
|
|
145
|
+
- uses: actions/checkout@v2
|
|
146
|
+
|
|
147
|
+
- name: Create Release
|
|
148
|
+
id: create_release
|
|
149
|
+
uses: softprops/action-gh-release@v1
|
|
150
|
+
with:
|
|
151
|
+
tag_name: v${{ needs.load-pkg-version.outputs.version }}
|
|
152
|
+
name: Release v${{ needs.load-pkg-version.outputs.version }}
|
|
153
|
+
body: ${{ github.event.inputs.release_notes }}
|
|
154
|
+
draft: false
|
|
155
|
+
prerelease: false
|
|
156
|
+
files: |
|
|
157
|
+
dist/*.tar.gz
|
|
158
|
+
dist/*.whl
|
|
159
|
+
env:
|
|
160
|
+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
*.pyc
|
|
2
|
+
.coverage
|
|
3
|
+
coverage.*
|
|
4
|
+
|
|
5
|
+
# Documentation builds
|
|
6
|
+
docs/_build/
|
|
7
|
+
docs/_static/
|
|
8
|
+
docs/_templates/
|
|
9
|
+
|
|
10
|
+
# IDE
|
|
11
|
+
.vscode/
|
|
12
|
+
.idea/
|
|
13
|
+
*.swp
|
|
14
|
+
*.swo
|
|
15
|
+
|
|
16
|
+
# OSX
|
|
17
|
+
.DS_Store
|
|
18
|
+
Thumbs.db
|
|
19
|
+
|
|
20
|
+
# Python
|
|
21
|
+
__pycache__/
|
|
22
|
+
*.py[cod]
|
|
23
|
+
*$py.class
|
|
24
|
+
*.so
|
|
25
|
+
.Python
|
|
26
|
+
build/
|
|
27
|
+
develop-eggs/
|
|
28
|
+
dist/
|
|
29
|
+
downloads/
|
|
30
|
+
eggs/
|
|
31
|
+
.eggs/
|
|
32
|
+
lib/
|
|
33
|
+
lib64/
|
|
34
|
+
parts/
|
|
35
|
+
sdist/
|
|
36
|
+
var/
|
|
37
|
+
wheels/
|
|
38
|
+
*.egg-info/
|
|
39
|
+
.installed.cfg
|
|
40
|
+
*.egg
|
|
41
|
+
MANIFEST
|
|
42
|
+
|
|
43
|
+
# Virtual environments
|
|
44
|
+
venv/
|
|
45
|
+
env/
|
|
46
|
+
ENV/
|
|
47
|
+
|
|
48
|
+
# Secrets
|
|
49
|
+
*.env
|
|
50
|
+
env.bat
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
{
|
|
2
|
+
"[python]": {
|
|
3
|
+
"editor.defaultFormatter": "ms-python.black-formatter",
|
|
4
|
+
"editor.formatOnSave": true
|
|
5
|
+
},
|
|
6
|
+
"editor.rulers": [120],
|
|
7
|
+
"python.formatting.blackArgs": [
|
|
8
|
+
"--line-length=120"
|
|
9
|
+
],
|
|
10
|
+
"python-envs.defaultEnvManager": "ms-python.python:conda",
|
|
11
|
+
"python-envs.defaultPackageManager": "ms-python.python:conda",
|
|
12
|
+
"python-envs.pythonProjects": [],
|
|
13
|
+
"python.testing.pytestArgs": [
|
|
14
|
+
"tests"
|
|
15
|
+
],
|
|
16
|
+
"python.testing.unittestEnabled": false,
|
|
17
|
+
"python.testing.pytestEnabled": true,
|
|
18
|
+
"python.testing.unittestArgs": [
|
|
19
|
+
"-v",
|
|
20
|
+
"-s",
|
|
21
|
+
"./tests",
|
|
22
|
+
"-p",
|
|
23
|
+
"test_*.py"
|
|
24
|
+
]
|
|
25
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 TextVerified
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|