http2py 0.1.31__tar.gz → 0.1.33__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.
- http2py-0.1.33/.gitattributes +1 -0
- http2py-0.1.33/.github/workflows/ci.yml +236 -0
- http2py-0.1.33/.gitignore +112 -0
- {http2py-0.1.31 → http2py-0.1.33}/PKG-INFO +28 -13
- {http2py-0.1.31 → http2py-0.1.33}/README.md +4 -2
- http2py-0.1.33/conftest.py +21 -0
- {http2py-0.1.31 → http2py-0.1.33}/http2py/api_pkg_maker.py +11 -0
- {http2py-0.1.31 → http2py-0.1.33}/http2py/authentication.py +7 -0
- {http2py-0.1.31 → http2py-0.1.33}/http2py/cli_maker.py +6 -0
- {http2py-0.1.31 → http2py-0.1.33}/http2py/client.py +6 -0
- {http2py-0.1.31 → http2py-0.1.33}/http2py/constants.py +2 -0
- {http2py-0.1.31 → http2py-0.1.33}/http2py/decorators.py +7 -0
- {http2py-0.1.31 → http2py-0.1.33}/http2py/default_configs.py +2 -0
- {http2py-0.1.31 → http2py-0.1.33}/http2py/example_cli.py +2 -0
- {http2py-0.1.31 → http2py-0.1.33}/http2py/global_state.py +2 -0
- {http2py-0.1.31 → http2py-0.1.33}/http2py/py2request.py +6 -6
- {http2py-0.1.31 → http2py-0.1.33}/http2py/testing_utils.py +6 -0
- http2py-0.1.33/http2py/tests/__init__.py +1 -0
- http2py-0.1.33/http2py/tests/conftest.py +44 -0
- http2py-0.1.33/http2py/tests/test_requirements.txt +1 -0
- {http2py-0.1.31 → http2py-0.1.33}/http2py/util.py +14 -4
- http2py-0.1.33/pyproject.toml +190 -0
- http2py-0.1.33/tests/test_ci_collection_contract.py +139 -0
- http2py-0.1.33/tests/test_dependency_workarounds.py +85 -0
- http2py-0.1.33/tests/test_smoke.py +84 -0
- http2py-0.1.31/http2py/tests/conftest.py +0 -30
- http2py-0.1.31/http2py.egg-info/PKG-INFO +0 -88
- http2py-0.1.31/http2py.egg-info/SOURCES.txt +0 -28
- http2py-0.1.31/http2py.egg-info/dependency_links.txt +0 -1
- http2py-0.1.31/http2py.egg-info/entry_points.txt +0 -2
- http2py-0.1.31/http2py.egg-info/not-zip-safe +0 -1
- http2py-0.1.31/http2py.egg-info/requires.txt +0 -7
- http2py-0.1.31/http2py.egg-info/top_level.txt +0 -1
- http2py-0.1.31/setup.cfg +0 -43
- http2py-0.1.31/setup.py +0 -3
- {http2py-0.1.31 → http2py-0.1.33}/LICENSE +0 -0
- {http2py-0.1.31 → http2py-0.1.33}/http2py/__init__.py +0 -0
- {http2py-0.1.31 → http2py-0.1.33}/http2py/http2py_cls.py +0 -0
- /http2py-0.1.31/http2py/tests/__init__.py → /http2py-0.1.33/http2py/resources/module_maker/func_tpl.txt +0 -0
- {http2py-0.1.31 → http2py-0.1.33}/http2py/tests/api_pkg_maker_test.py +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
*.ipynb linguist-documentation
|
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
name: Continuous Integration (uv)
|
|
2
|
+
# NOTE: publishing uses `uv publish`, which reads UV_PUBLISH_TOKEN -- mapped here
|
|
3
|
+
# from secrets.PYPI_PASSWORD. This repo has no repository-level secrets; it
|
|
4
|
+
# inherits the organization-level PYPI_PASSWORD / SSH_PRIVATE_KEY (visibility:
|
|
5
|
+
# all), which is the same pair other migrated packages in this org publish with.
|
|
6
|
+
#
|
|
7
|
+
# The GitHub Pages job below is gated on [tool.wads.ci.docs].enabled, which is
|
|
8
|
+
# false here: docs/ and docsrc/ were removed from this repo, and the legacy CI's
|
|
9
|
+
# `epythet make . github` call against the now-absent docs is what broke Publish.
|
|
10
|
+
on: [push, pull_request]
|
|
11
|
+
|
|
12
|
+
# Note: Environment variables (PROJECT_NAME and vars from [tool.wads.ci.env])
|
|
13
|
+
# are set by the read-ci-config action in the setup job and made available
|
|
14
|
+
# to all subsequent jobs via GITHUB_ENV
|
|
15
|
+
|
|
16
|
+
jobs:
|
|
17
|
+
# First job: Read configuration from pyproject.toml
|
|
18
|
+
setup:
|
|
19
|
+
name: Read Configuration
|
|
20
|
+
runs-on: ubuntu-latest
|
|
21
|
+
outputs:
|
|
22
|
+
project-name: ${{ steps.config.outputs.project-name }}
|
|
23
|
+
python-versions: ${{ steps.config.outputs.python-versions }}
|
|
24
|
+
pytest-args: ${{ steps.config.outputs.pytest-args }}
|
|
25
|
+
coverage-enabled: ${{ steps.config.outputs.coverage-enabled }}
|
|
26
|
+
exclude-paths: ${{ steps.config.outputs.exclude-paths }}
|
|
27
|
+
test-on-windows: ${{ steps.config.outputs.test-on-windows }}
|
|
28
|
+
build-sdist: ${{ steps.config.outputs.build-sdist }}
|
|
29
|
+
build-wheel: ${{ steps.config.outputs.build-wheel }}
|
|
30
|
+
metrics-enabled: ${{ steps.config.outputs.metrics-enabled }}
|
|
31
|
+
metrics-config-path: ${{ steps.config.outputs.metrics-config-path }}
|
|
32
|
+
metrics-storage-branch: ${{ steps.config.outputs.metrics-storage-branch }}
|
|
33
|
+
metrics-python-version: ${{ steps.config.outputs.metrics-python-version }}
|
|
34
|
+
metrics-force-run: ${{ steps.config.outputs.metrics-force-run }}
|
|
35
|
+
ruff-enabled: ${{ steps.config.outputs.ruff-enabled }}
|
|
36
|
+
black-enabled: ${{ steps.config.outputs.black-enabled }}
|
|
37
|
+
mypy-enabled: ${{ steps.config.outputs.mypy-enabled }}
|
|
38
|
+
docs-enabled: ${{ steps.config.outputs.docs-enabled }}
|
|
39
|
+
|
|
40
|
+
steps:
|
|
41
|
+
- uses: actions/checkout@v6
|
|
42
|
+
|
|
43
|
+
- name: Set up uv
|
|
44
|
+
uses: astral-sh/setup-uv@v7
|
|
45
|
+
|
|
46
|
+
- name: Set up Python
|
|
47
|
+
run: uv python install 3.11
|
|
48
|
+
|
|
49
|
+
- name: Read CI Config
|
|
50
|
+
id: config
|
|
51
|
+
uses: i2mint/wads/actions/read-ci-config@master
|
|
52
|
+
with:
|
|
53
|
+
pyproject-path: .
|
|
54
|
+
|
|
55
|
+
# Second job: Validation using the config
|
|
56
|
+
validation:
|
|
57
|
+
name: Validation
|
|
58
|
+
if: "!contains(github.event.head_commit.message, '[skip ci]')"
|
|
59
|
+
needs: setup
|
|
60
|
+
runs-on: ubuntu-latest
|
|
61
|
+
strategy:
|
|
62
|
+
matrix:
|
|
63
|
+
python-version: ${{ fromJson(needs.setup.outputs.python-versions) }}
|
|
64
|
+
|
|
65
|
+
steps:
|
|
66
|
+
- uses: actions/checkout@v6
|
|
67
|
+
|
|
68
|
+
- name: Set up uv
|
|
69
|
+
uses: astral-sh/setup-uv@v7
|
|
70
|
+
with:
|
|
71
|
+
enable-cache: true
|
|
72
|
+
|
|
73
|
+
- name: Set up Python ${{ matrix.python-version }}
|
|
74
|
+
uses: i2mint/wads/actions/setup-python-uv@master
|
|
75
|
+
with:
|
|
76
|
+
python-version: ${{ matrix.python-version }}
|
|
77
|
+
|
|
78
|
+
- name: Install System Dependencies
|
|
79
|
+
uses: i2mint/wads/actions/install-system-deps@master
|
|
80
|
+
with:
|
|
81
|
+
pyproject-path: .
|
|
82
|
+
|
|
83
|
+
- name: Install Dependencies
|
|
84
|
+
uses: i2mint/wads/actions/install-deps-uv@master
|
|
85
|
+
|
|
86
|
+
- name: Format Source Code
|
|
87
|
+
if: needs.setup.outputs.ruff-enabled != 'false'
|
|
88
|
+
run: uvx ruff format .
|
|
89
|
+
|
|
90
|
+
- name: Format Source Code (black)
|
|
91
|
+
if: needs.setup.outputs.black-enabled == 'true'
|
|
92
|
+
run: uvx black .
|
|
93
|
+
|
|
94
|
+
- name: Lint Validation
|
|
95
|
+
if: needs.setup.outputs.ruff-enabled != 'false'
|
|
96
|
+
run: uvx ruff check --output-format=github ${{ needs.setup.outputs.project-name }}
|
|
97
|
+
|
|
98
|
+
- name: Type Check (mypy)
|
|
99
|
+
if: needs.setup.outputs.mypy-enabled == 'true'
|
|
100
|
+
run: uvx mypy ${{ needs.setup.outputs.project-name }}
|
|
101
|
+
|
|
102
|
+
- name: Run Tests
|
|
103
|
+
uses: i2mint/wads/actions/run-tests-uv@master
|
|
104
|
+
with:
|
|
105
|
+
root-dir: ${{ needs.setup.outputs.project-name }}
|
|
106
|
+
pytest-args: ${{ needs.setup.outputs.pytest-args }}
|
|
107
|
+
exclude-paths: ${{ needs.setup.outputs.exclude-paths }}
|
|
108
|
+
coverage: ${{ needs.setup.outputs.coverage-enabled }}
|
|
109
|
+
|
|
110
|
+
- name: Track Code Metrics
|
|
111
|
+
if: needs.setup.outputs.metrics-enabled == 'true'
|
|
112
|
+
uses: i2mint/umpyre/actions/track-metrics@master
|
|
113
|
+
continue-on-error: true
|
|
114
|
+
with:
|
|
115
|
+
github-token: ${{ secrets.GITHUB_TOKEN }}
|
|
116
|
+
config-path: ${{ needs.setup.outputs.metrics-config-path }}
|
|
117
|
+
storage-branch: ${{ needs.setup.outputs.metrics-storage-branch }}
|
|
118
|
+
python-version: ${{ needs.setup.outputs.metrics-python-version }}
|
|
119
|
+
force-run: ${{ needs.setup.outputs.metrics-force-run }}
|
|
120
|
+
|
|
121
|
+
# Optional Windows testing (if enabled in config)
|
|
122
|
+
windows-validation:
|
|
123
|
+
name: Windows Tests
|
|
124
|
+
if: "!contains(github.event.head_commit.message, '[skip ci]') && needs.setup.outputs.test-on-windows == 'true'"
|
|
125
|
+
needs: setup
|
|
126
|
+
runs-on: windows-latest
|
|
127
|
+
continue-on-error: true
|
|
128
|
+
|
|
129
|
+
steps:
|
|
130
|
+
- uses: actions/checkout@v6
|
|
131
|
+
|
|
132
|
+
- name: Set up uv
|
|
133
|
+
uses: astral-sh/setup-uv@v7
|
|
134
|
+
with:
|
|
135
|
+
enable-cache: true
|
|
136
|
+
|
|
137
|
+
- name: Set up Python
|
|
138
|
+
uses: i2mint/wads/actions/setup-python-uv@master
|
|
139
|
+
with:
|
|
140
|
+
python-version: ${{ fromJson(needs.setup.outputs.python-versions)[0] }}
|
|
141
|
+
|
|
142
|
+
- name: Install System Dependencies
|
|
143
|
+
uses: i2mint/wads/actions/install-system-deps@master
|
|
144
|
+
with:
|
|
145
|
+
pyproject-path: .
|
|
146
|
+
|
|
147
|
+
- name: Install Dependencies
|
|
148
|
+
uses: i2mint/wads/actions/install-deps-uv@master
|
|
149
|
+
|
|
150
|
+
- name: Run Tests
|
|
151
|
+
uses: i2mint/wads/actions/run-tests-uv@master
|
|
152
|
+
with:
|
|
153
|
+
root-dir: ${{ needs.setup.outputs.project-name }}
|
|
154
|
+
pytest-args: ${{ needs.setup.outputs.pytest-args }}
|
|
155
|
+
exclude-paths: ${{ needs.setup.outputs.exclude-paths }}
|
|
156
|
+
|
|
157
|
+
# Publishing job
|
|
158
|
+
publish:
|
|
159
|
+
name: Publish
|
|
160
|
+
permissions:
|
|
161
|
+
contents: write
|
|
162
|
+
if: "!contains(github.event.head_commit.message, '[skip ci]') && (github.ref == 'refs/heads/master' || github.ref == 'refs/heads/main')"
|
|
163
|
+
needs: [setup, validation]
|
|
164
|
+
runs-on: ubuntu-latest
|
|
165
|
+
|
|
166
|
+
steps:
|
|
167
|
+
- uses: actions/checkout@v6
|
|
168
|
+
with:
|
|
169
|
+
fetch-depth: 0
|
|
170
|
+
token: ${{ secrets.GITHUB_TOKEN }}
|
|
171
|
+
|
|
172
|
+
- name: Set up uv
|
|
173
|
+
uses: astral-sh/setup-uv@v7
|
|
174
|
+
|
|
175
|
+
- name: Set up Python
|
|
176
|
+
uses: i2mint/wads/actions/setup-python-uv@master
|
|
177
|
+
with:
|
|
178
|
+
python-version: ${{ fromJson(needs.setup.outputs.python-versions)[0] }}
|
|
179
|
+
create-venv: "false"
|
|
180
|
+
|
|
181
|
+
- name: Format Source Code
|
|
182
|
+
if: needs.setup.outputs.ruff-enabled != 'false'
|
|
183
|
+
run: uvx ruff format .
|
|
184
|
+
|
|
185
|
+
- name: Format Source Code (black)
|
|
186
|
+
if: needs.setup.outputs.black-enabled == 'true'
|
|
187
|
+
run: uvx black .
|
|
188
|
+
|
|
189
|
+
- name: Update Version Number
|
|
190
|
+
id: version
|
|
191
|
+
uses: i2mint/isee/actions/bump-version-number@master
|
|
192
|
+
|
|
193
|
+
- name: Build Distribution
|
|
194
|
+
uses: i2mint/wads/actions/build-dist-uv@master
|
|
195
|
+
with:
|
|
196
|
+
sdist: ${{ needs.setup.outputs.build-sdist }}
|
|
197
|
+
wheel: ${{ needs.setup.outputs.build-wheel }}
|
|
198
|
+
|
|
199
|
+
- name: Publish to PyPI
|
|
200
|
+
uses: i2mint/wads/actions/pypi-publish-uv@master
|
|
201
|
+
with:
|
|
202
|
+
pypi-token: ${{ secrets.PYPI_PASSWORD }}
|
|
203
|
+
|
|
204
|
+
- name: Force SSH for git remote
|
|
205
|
+
run: git remote set-url origin git@github.com:${{ github.repository }}.git
|
|
206
|
+
|
|
207
|
+
- name: Commit Changes
|
|
208
|
+
uses: i2mint/wads/actions/git-commit@master
|
|
209
|
+
with:
|
|
210
|
+
commit-message: "**CI** Formatted code + Updated version to ${{ env.VERSION }} [skip ci]"
|
|
211
|
+
ssh-private-key: ${{ secrets.SSH_PRIVATE_KEY }}
|
|
212
|
+
push: true
|
|
213
|
+
|
|
214
|
+
- name: Tag Repository
|
|
215
|
+
uses: i2mint/wads/actions/git-tag@master
|
|
216
|
+
with:
|
|
217
|
+
tag: ${{ env.VERSION }}
|
|
218
|
+
message: "Release version ${{ env.VERSION }}"
|
|
219
|
+
push: true
|
|
220
|
+
|
|
221
|
+
# Optional GitHub Pages (skipped when [tool.wads.ci.docs].enabled = false)
|
|
222
|
+
github-pages:
|
|
223
|
+
name: Publish GitHub Pages
|
|
224
|
+
permissions:
|
|
225
|
+
contents: write
|
|
226
|
+
pages: write
|
|
227
|
+
id-token: write
|
|
228
|
+
if: "!contains(github.event.head_commit.message, '[skip ci]') && github.ref == format('refs/heads/{0}', github.event.repository.default_branch) && needs.setup.outputs.docs-enabled != 'false'"
|
|
229
|
+
needs: [setup, publish]
|
|
230
|
+
runs-on: ubuntu-latest
|
|
231
|
+
|
|
232
|
+
steps:
|
|
233
|
+
- uses: i2mint/epythet/actions/publish-github-pages@master
|
|
234
|
+
with:
|
|
235
|
+
github-token: ${{ secrets.GITHUB_TOKEN }}
|
|
236
|
+
ignore: "tests/,scrap/,examples/"
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
docs/*
|
|
2
|
+
# Byte-compiled / optimized / DLL files
|
|
3
|
+
__pycache__/
|
|
4
|
+
*.py[cod]
|
|
5
|
+
*$py.class
|
|
6
|
+
|
|
7
|
+
.DS_Store
|
|
8
|
+
# C extensions
|
|
9
|
+
*.so
|
|
10
|
+
|
|
11
|
+
# Distribution / packaging
|
|
12
|
+
.Python
|
|
13
|
+
build/
|
|
14
|
+
develop-eggs/
|
|
15
|
+
dist/
|
|
16
|
+
downloads/
|
|
17
|
+
eggs/
|
|
18
|
+
.eggs/
|
|
19
|
+
lib/
|
|
20
|
+
lib64/
|
|
21
|
+
parts/
|
|
22
|
+
sdist/
|
|
23
|
+
var/
|
|
24
|
+
wheels/
|
|
25
|
+
*.egg-info/
|
|
26
|
+
.installed.cfg
|
|
27
|
+
*.egg
|
|
28
|
+
MANIFEST
|
|
29
|
+
|
|
30
|
+
# PyInstaller
|
|
31
|
+
# Usually these files are written by a python script from a template
|
|
32
|
+
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
|
33
|
+
*.manifest
|
|
34
|
+
*.spec
|
|
35
|
+
|
|
36
|
+
# Installer logs
|
|
37
|
+
pip-log.txt
|
|
38
|
+
pip-delete-this-directory.txt
|
|
39
|
+
|
|
40
|
+
# Unit test / coverage reports
|
|
41
|
+
htmlcov/
|
|
42
|
+
.tox/
|
|
43
|
+
.coverage
|
|
44
|
+
.coverage.*
|
|
45
|
+
.cache
|
|
46
|
+
nosetests.xml
|
|
47
|
+
coverage.xml
|
|
48
|
+
*.cover
|
|
49
|
+
.hypothesis/
|
|
50
|
+
.pytest_cache/
|
|
51
|
+
|
|
52
|
+
# Translations
|
|
53
|
+
*.mo
|
|
54
|
+
*.pot
|
|
55
|
+
|
|
56
|
+
# Django stuff:
|
|
57
|
+
*.log
|
|
58
|
+
local_settings.py
|
|
59
|
+
db.sqlite3
|
|
60
|
+
|
|
61
|
+
# Flask stuff:
|
|
62
|
+
instance/
|
|
63
|
+
.webassets-cache
|
|
64
|
+
|
|
65
|
+
# Scrapy stuff:
|
|
66
|
+
.scrapy
|
|
67
|
+
|
|
68
|
+
# Sphinx documentation
|
|
69
|
+
docs/_build/
|
|
70
|
+
|
|
71
|
+
# PyBuilder
|
|
72
|
+
target/
|
|
73
|
+
|
|
74
|
+
# Jupyter Notebook
|
|
75
|
+
.ipynb_checkpoints
|
|
76
|
+
|
|
77
|
+
# pyenv
|
|
78
|
+
.python-version
|
|
79
|
+
|
|
80
|
+
# celery beat schedule file
|
|
81
|
+
celerybeat-schedule
|
|
82
|
+
|
|
83
|
+
# SageMath parsed files
|
|
84
|
+
*.sage.py
|
|
85
|
+
|
|
86
|
+
# Environments
|
|
87
|
+
.env
|
|
88
|
+
.venv
|
|
89
|
+
env/
|
|
90
|
+
venv/
|
|
91
|
+
ENV/
|
|
92
|
+
env.bak/
|
|
93
|
+
venv.bak/
|
|
94
|
+
|
|
95
|
+
# Spyder project settings
|
|
96
|
+
.spyderproject
|
|
97
|
+
.spyproject
|
|
98
|
+
|
|
99
|
+
# Rope project settings
|
|
100
|
+
.ropeproject
|
|
101
|
+
|
|
102
|
+
# mkdocs documentation
|
|
103
|
+
/site
|
|
104
|
+
|
|
105
|
+
# mypy
|
|
106
|
+
.mypy_cache/
|
|
107
|
+
|
|
108
|
+
# PyCharm
|
|
109
|
+
.idea
|
|
110
|
+
|
|
111
|
+
# VS Code
|
|
112
|
+
.vscode
|
|
@@ -1,28 +1,43 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
2
|
Name: http2py
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.33
|
|
4
4
|
Summary: Tools to create python binders to http web services.
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
Description-Content-Type: text/markdown
|
|
5
|
+
Project-URL: Homepage, https://github.com/i2mint/http2py
|
|
6
|
+
Project-URL: Repository, https://github.com/i2mint/http2py
|
|
7
|
+
Author: Otosense
|
|
8
|
+
License-Expression: Apache-2.0
|
|
10
9
|
License-File: LICENSE
|
|
10
|
+
Keywords: API,http,requests,webservice
|
|
11
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: Programming Language :: Python :: 3
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
16
|
+
Classifier: Topic :: Internet :: WWW/HTTP
|
|
17
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
18
|
+
Requires-Python: >=3.10
|
|
19
|
+
Requires-Dist: argh
|
|
20
|
+
Requires-Dist: dill
|
|
11
21
|
Requires-Dist: glom
|
|
12
22
|
Requires-Dist: i2
|
|
23
|
+
Requires-Dist: importlib-resources
|
|
13
24
|
Requires-Dist: ju
|
|
25
|
+
Requires-Dist: pyyaml
|
|
14
26
|
Requires-Dist: requests
|
|
15
|
-
|
|
16
|
-
Requires-Dist:
|
|
17
|
-
Requires-Dist:
|
|
18
|
-
|
|
27
|
+
Provides-Extra: dev
|
|
28
|
+
Requires-Dist: pytest-cov>=4.0; extra == 'dev'
|
|
29
|
+
Requires-Dist: pytest>=7.0; extra == 'dev'
|
|
30
|
+
Requires-Dist: ruff>=0.1.0; extra == 'dev'
|
|
31
|
+
Description-Content-Type: text/markdown
|
|
32
|
+
|
|
33
|
+
**Note: A new, lighterweight, more modern replacement: [ho](https://github.com/i2mint/ho)**
|
|
34
|
+
|
|
35
|
+
# (Http) Requests for humans
|
|
19
36
|
|
|
20
37
|
[Documentation here](https://i2mint.github.io/http2py/)
|
|
21
38
|
|
|
22
39
|
`the_one_where_we_have_an_http_service_that_we_want_call_through_normal_looking_python_functions`
|
|
23
40
|
|
|
24
|
-
# (Http) Requests for humans
|
|
25
|
-
|
|
26
41
|
Tools to create python binders to http web services.
|
|
27
42
|
Here, we develop python data access to web content through http request such as web services or web pages.
|
|
28
43
|
|
|
@@ -1,9 +1,11 @@
|
|
|
1
|
+
**Note: A new, lighterweight, more modern replacement: [ho](https://github.com/i2mint/ho)**
|
|
2
|
+
|
|
3
|
+
# (Http) Requests for humans
|
|
4
|
+
|
|
1
5
|
[Documentation here](https://i2mint.github.io/http2py/)
|
|
2
6
|
|
|
3
7
|
`the_one_where_we_have_an_http_service_that_we_want_call_through_normal_looking_python_functions`
|
|
4
8
|
|
|
5
|
-
# (Http) Requests for humans
|
|
6
|
-
|
|
7
9
|
Tools to create python binders to http web services.
|
|
8
10
|
Here, we develop python data access to web content through http request such as web services or web pages.
|
|
9
11
|
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"""Pytest configuration for the http2py repository.
|
|
2
|
+
|
|
3
|
+
``http2py.api_pkg_maker`` imports ``setuptools.sandbox``, which modern
|
|
4
|
+
setuptools no longer ships, so merely *importing* the module raises
|
|
5
|
+
``ImportError``. Under ``--doctest-modules`` that is not a single failing test:
|
|
6
|
+
it aborts collection for the whole session. The module is deliberately left in
|
|
7
|
+
place (whether to rewrite it or remove it is still open on issue #14), so it is
|
|
8
|
+
excluded from collection instead.
|
|
9
|
+
|
|
10
|
+
CI excludes the same two paths via ``[tool.wads.ci.testing].exclude_paths`` in
|
|
11
|
+
pyproject.toml, which the wads ``run-tests-uv`` action turns into ``--ignore``
|
|
12
|
+
flags. Repeating them here is what makes a bare ``pytest`` (no flags, e.g. a
|
|
13
|
+
local run or an editor's test runner) behave the same way as CI.
|
|
14
|
+
``tests/test_ci_collection_contract.py`` asserts the two lists stay in
|
|
15
|
+
agreement, so they cannot drift apart silently.
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
collect_ignore = [
|
|
19
|
+
"http2py/api_pkg_maker.py",
|
|
20
|
+
"http2py/tests",
|
|
21
|
+
]
|
|
@@ -1,3 +1,14 @@
|
|
|
1
|
+
"""Generate an installable python package from an OpenAPI specification.
|
|
2
|
+
|
|
3
|
+
Given a spec (or the URL of one), :func:`mk_api_pkg` writes a small source
|
|
4
|
+
distribution whose functions are bound to the service's routes.
|
|
5
|
+
|
|
6
|
+
Note: this module imports ``setuptools.sandbox``, which modern setuptools no
|
|
7
|
+
longer provides, so importing it raises ``ImportError``. It is kept in place
|
|
8
|
+
pending a decision (rewrite or remove) and is excluded from test collection;
|
|
9
|
+
see the repo-root ``conftest.py``.
|
|
10
|
+
"""
|
|
11
|
+
|
|
1
12
|
import argh
|
|
2
13
|
import os
|
|
3
14
|
import shutil
|
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
"""Resolve credentials and build the auth callables that requests will use.
|
|
2
|
+
|
|
3
|
+
:func:`mk_auth` turns an auth specification -- inline values, environment
|
|
4
|
+
variables, or a JSON credentials file -- into something the request layer can
|
|
5
|
+
attach to outgoing calls.
|
|
6
|
+
"""
|
|
7
|
+
|
|
1
8
|
import json
|
|
2
9
|
import os
|
|
3
10
|
from pathlib import Path
|
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
"""Turn an http-bound python object into a command line interface.
|
|
2
|
+
|
|
3
|
+
Signatures are first made argparse-friendly (:func:`mk_argparse_friendly`),
|
|
4
|
+
then dispatched with ``argh`` by :func:`mk_cli` / :func:`dispatch_cli`.
|
|
5
|
+
"""
|
|
6
|
+
|
|
1
7
|
import argh
|
|
2
8
|
from functools import wraps
|
|
3
9
|
from glom import glom
|
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
"""The main entry point: a python object facading an http service.
|
|
2
|
+
|
|
3
|
+
:class:`HttpClient` takes an OpenAPI specification (a dict, or the URL of one)
|
|
4
|
+
and exposes each declared route as a normal python method.
|
|
5
|
+
"""
|
|
6
|
+
|
|
1
7
|
from glom import glom
|
|
2
8
|
from requests import request, get, Session
|
|
3
9
|
from i2.errors import AuthorizationError
|
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
"""Response handling: map http status codes to exceptions, decode the payload.
|
|
2
|
+
|
|
3
|
+
``handle_json_resp`` / ``handle_binary_resp`` / ``handle_raw_resp`` wrap an
|
|
4
|
+
output transformation so it only ever sees a successful response of the
|
|
5
|
+
expected content type.
|
|
6
|
+
"""
|
|
7
|
+
|
|
1
8
|
from functools import partial
|
|
2
9
|
from i2.errors import (
|
|
3
10
|
AuthorizationError,
|
|
@@ -305,9 +305,9 @@ def mk_request_function(
|
|
|
305
305
|
if docstring:
|
|
306
306
|
request_func.__doc__ = docstring
|
|
307
307
|
|
|
308
|
-
assert callable(
|
|
309
|
-
output_trans
|
|
310
|
-
)
|
|
308
|
+
assert callable(output_trans), (
|
|
309
|
+
f"output_trans {output_trans} is not callable, try again"
|
|
310
|
+
)
|
|
311
311
|
return request_func
|
|
312
312
|
|
|
313
313
|
|
|
@@ -452,9 +452,9 @@ def _mk_method_func_and_wrap(method_spec, method_func_from_method_spec):
|
|
|
452
452
|
|
|
453
453
|
|
|
454
454
|
def _mk_signature_from_names(arg_names, pk_names):
|
|
455
|
-
assert set(pk_names) <= set(
|
|
456
|
-
|
|
457
|
-
)
|
|
455
|
+
assert set(pk_names) <= set(arg_names), (
|
|
456
|
+
"The query_arg_names must be a subset of the names in the url_template"
|
|
457
|
+
)
|
|
458
458
|
ko_names = _difference_conserving_order(arg_names, pk_names)
|
|
459
459
|
if ko_names:
|
|
460
460
|
ko_names_str = "*, " + ", ".join(ko_names)
|
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
"""Helpers for testing code that talks to an http service.
|
|
2
|
+
|
|
3
|
+
:class:`MockHttpClient` answers without touching the network, and
|
|
4
|
+
:func:`mk_unit_tests` generates test stubs from a client's bound methods.
|
|
5
|
+
"""
|
|
6
|
+
|
|
1
7
|
from http2py.client import HttpClient
|
|
2
8
|
|
|
3
9
|
TEST_NUMBER = 100
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Tests for http2py that require a live py2http service to be running."""
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
"""Fixtures for the live-service tests in this directory.
|
|
2
|
+
|
|
3
|
+
These tests stand up a real ``py2http`` web service and talk to it, so
|
|
4
|
+
``py2http`` is a test-only requirement (see ``test_requirements.txt``) and is
|
|
5
|
+
*not* one of http2py's declared dependencies.
|
|
6
|
+
|
|
7
|
+
It is imported inside the fixture rather than at module level on purpose:
|
|
8
|
+
pytest eagerly imports the ``conftest.py`` of any ``test*`` sub-directory of a
|
|
9
|
+
collection root, and it does so *before* ``--ignore`` is applied. A module-level
|
|
10
|
+
``from py2http import run_app`` therefore aborted the entire session with
|
|
11
|
+
"ImportError while loading conftest" on any machine (CI included) that has no
|
|
12
|
+
py2http installed -- even though this directory is excluded from collection.
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
import pytest
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def foo(a: int = 0, b: int = 0, c=0):
|
|
19
|
+
"""This is foo. It computes something"""
|
|
20
|
+
return (a * b) + c
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def bar(x, greeting="hello"):
|
|
24
|
+
"""bar greets its input"""
|
|
25
|
+
return f"{greeting} {x}"
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def confuser(a: int = 0, x: float = 3.14):
|
|
29
|
+
return (a**2) * x
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
@pytest.fixture(scope="session", autouse=True)
|
|
33
|
+
def ws_app():
|
|
34
|
+
from py2http import run_app
|
|
35
|
+
from py2http.util import run_process
|
|
36
|
+
|
|
37
|
+
with run_process(
|
|
38
|
+
func=run_app,
|
|
39
|
+
func_kwargs=dict(
|
|
40
|
+
app_obj=[foo, bar, confuser], publish_openapi=True, server="wsgiref"
|
|
41
|
+
),
|
|
42
|
+
is_ready=3,
|
|
43
|
+
) as proc:
|
|
44
|
+
yield proc
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
py2http
|
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
"""Small general-purpose helpers: data files, dict defaults, JSON-ability checks.
|
|
2
|
+
|
|
3
|
+
Also holds the friendly ``ModuleNotFoundError`` messages used to point a user at
|
|
4
|
+
the right install when an optional dependency is missing.
|
|
5
|
+
"""
|
|
6
|
+
|
|
1
7
|
import json
|
|
2
8
|
|
|
3
9
|
try:
|
|
@@ -26,7 +32,8 @@ class ModuleNotFoundErrorNiceMessage:
|
|
|
26
32
|
|
|
27
33
|
def __exit__(self, exc_type, exc_val, exc_tb):
|
|
28
34
|
if exc_type is ModuleNotFoundError:
|
|
29
|
-
raise ModuleNotFoundError(
|
|
35
|
+
raise ModuleNotFoundError(
|
|
36
|
+
f"""
|
|
30
37
|
It seems you don't have requred `{exc_val.name}` package.
|
|
31
38
|
Try installing it by running:
|
|
32
39
|
|
|
@@ -34,7 +41,8 @@ Try installing it by running:
|
|
|
34
41
|
|
|
35
42
|
in your terminal.
|
|
36
43
|
For more information: https://pypi.org/project/{exc_val.name}
|
|
37
|
-
"""
|
|
44
|
+
"""
|
|
45
|
+
)
|
|
38
46
|
|
|
39
47
|
|
|
40
48
|
class I2mintModuleNotFoundErrorNiceMessage:
|
|
@@ -43,11 +51,13 @@ class I2mintModuleNotFoundErrorNiceMessage:
|
|
|
43
51
|
|
|
44
52
|
def __exit__(self, exc_type, exc_val, exc_tb):
|
|
45
53
|
if exc_type is ModuleNotFoundError:
|
|
46
|
-
raise ModuleNotFoundError(
|
|
54
|
+
raise ModuleNotFoundError(
|
|
55
|
+
f"""
|
|
47
56
|
It seems you don't have requred `{exc_val.name}` package. Not sure if this is the problem, but you could try:
|
|
48
57
|
git clone https://github.com/i2mint/{exc_val.name}
|
|
49
58
|
in a place that your python path (i.e. PYTHONPATH environment variable).
|
|
50
|
-
"""
|
|
59
|
+
"""
|
|
60
|
+
)
|
|
51
61
|
|
|
52
62
|
|
|
53
63
|
def is_jsonable(x):
|