http2py 0.1.30__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.30 → http2py-0.1.33}/PKG-INFO +32 -9
- {http2py-0.1.30 → http2py-0.1.33}/README.md +4 -2
- http2py-0.1.33/conftest.py +21 -0
- {http2py-0.1.30 → http2py-0.1.33}/http2py/api_pkg_maker.py +11 -0
- {http2py-0.1.30 → http2py-0.1.33}/http2py/authentication.py +8 -1
- {http2py-0.1.30 → http2py-0.1.33}/http2py/cli_maker.py +7 -1
- {http2py-0.1.30 → http2py-0.1.33}/http2py/client.py +6 -0
- {http2py-0.1.30 → http2py-0.1.33}/http2py/constants.py +2 -0
- {http2py-0.1.30 → http2py-0.1.33}/http2py/decorators.py +7 -0
- {http2py-0.1.30 → http2py-0.1.33}/http2py/default_configs.py +2 -0
- {http2py-0.1.30 → http2py-0.1.33}/http2py/example_cli.py +3 -1
- {http2py-0.1.30 → http2py-0.1.33}/http2py/global_state.py +2 -0
- {http2py-0.1.30 → http2py-0.1.33}/http2py/py2request.py +17 -15
- {http2py-0.1.30 → 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.30 → http2py-0.1.33}/http2py/util.py +6 -0
- 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.30/http2py/tests/conftest.py +0 -30
- http2py-0.1.30/http2py.egg-info/PKG-INFO +0 -80
- http2py-0.1.30/http2py.egg-info/SOURCES.txt +0 -28
- http2py-0.1.30/http2py.egg-info/dependency_links.txt +0 -1
- http2py-0.1.30/http2py.egg-info/entry_points.txt +0 -2
- http2py-0.1.30/http2py.egg-info/not-zip-safe +0 -1
- http2py-0.1.30/http2py.egg-info/requires.txt +0 -7
- http2py-0.1.30/http2py.egg-info/top_level.txt +0 -1
- http2py-0.1.30/setup.cfg +0 -43
- http2py-0.1.30/setup.py +0 -3
- {http2py-0.1.30 → http2py-0.1.33}/LICENSE +0 -0
- {http2py-0.1.30 → http2py-0.1.33}/http2py/__init__.py +0 -0
- {http2py-0.1.30 → http2py-0.1.33}/http2py/http2py_cls.py +0 -0
- /http2py-0.1.30/http2py/tests/__init__.py → /http2py-0.1.33/http2py/resources/module_maker/func_tpl.txt +0 -0
- {http2py-0.1.30 → 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,20 +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
|
|
21
|
+
Requires-Dist: glom
|
|
22
|
+
Requires-Dist: i2
|
|
23
|
+
Requires-Dist: importlib-resources
|
|
24
|
+
Requires-Dist: ju
|
|
25
|
+
Requires-Dist: pyyaml
|
|
26
|
+
Requires-Dist: requests
|
|
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
|
|
11
36
|
|
|
12
37
|
[Documentation here](https://i2mint.github.io/http2py/)
|
|
13
38
|
|
|
14
39
|
`the_one_where_we_have_an_http_service_that_we_want_call_through_normal_looking_python_functions`
|
|
15
40
|
|
|
16
|
-
# (Http) Requests for humans
|
|
17
|
-
|
|
18
41
|
Tools to create python binders to http web services.
|
|
19
42
|
Here, we develop python data access to web content through http request such as web services or web pages.
|
|
20
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,7 +1,14 @@
|
|
|
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
|
|
4
|
-
from
|
|
11
|
+
from collections.abc import Iterable
|
|
5
12
|
|
|
6
13
|
DFLT_CONFIG_FILENAME = os.path.join(Path.home(), ".http2py", "credentials.json")
|
|
7
14
|
|
|
@@ -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
|
|
@@ -6,7 +12,7 @@ import json
|
|
|
6
12
|
import os
|
|
7
13
|
from pathlib import Path
|
|
8
14
|
import requests
|
|
9
|
-
from
|
|
15
|
+
from collections.abc import Callable, Iterable
|
|
10
16
|
import yaml
|
|
11
17
|
|
|
12
18
|
from i2.io_trans import JSONAnnotAndDfltIoTrans
|
|
@@ -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,
|
|
@@ -1,5 +1,7 @@
|
|
|
1
|
+
"""A tiny worked example of the CLI-making tools, used by the docs and by hand."""
|
|
2
|
+
|
|
1
3
|
import argh
|
|
2
|
-
from
|
|
4
|
+
from collections.abc import Iterable
|
|
3
5
|
|
|
4
6
|
from http2py.cli_maker import mk_argparse_friendly
|
|
5
7
|
from i2.io_trans import AnnotAndDfltIoTrans
|
|
@@ -66,7 +66,7 @@ with I2mintModuleNotFoundErrorNiceMessage():
|
|
|
66
66
|
from i2.signatures import set_signature_of_func, KO
|
|
67
67
|
|
|
68
68
|
DFLT_PORT = 5000
|
|
69
|
-
DFLT_BASE_URL = "http://localhost:{
|
|
69
|
+
DFLT_BASE_URL = f"http://localhost:{DFLT_PORT}"
|
|
70
70
|
DFLT_REQUEST_METHOD = "post"
|
|
71
71
|
DFLT_REQUEST_KWARGS = imdict({"method": DFLT_REQUEST_METHOD, "url": ""})
|
|
72
72
|
|
|
@@ -227,7 +227,7 @@ def mk_request_function(
|
|
|
227
227
|
if "url_template" in method_spec:
|
|
228
228
|
url_template = method_spec["url_template"]
|
|
229
229
|
# Check if the url template already has parameters, add them otherwise
|
|
230
|
-
if query_arg_names and not re.search("^.*\?((.*=.*)(&?))+$", url_template):
|
|
230
|
+
if query_arg_names and not re.search(r"^.*\?((.*=.*)(&?))+$", url_template):
|
|
231
231
|
url_arg_parts = [f"{x}={{{x}}}" for x in query_arg_names if x in kwargs]
|
|
232
232
|
url_args = "&".join(url_arg_parts)
|
|
233
233
|
if url_args:
|
|
@@ -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
|
|
|
@@ -316,7 +316,7 @@ DFLT_METHOD_FUNC_FROM_METHOD_SPEC = mk_request_function
|
|
|
316
316
|
str_formatter = string.Formatter()
|
|
317
317
|
|
|
318
318
|
|
|
319
|
-
class Py2Request
|
|
319
|
+
class Py2Request:
|
|
320
320
|
"""Make a class that has methods that offer a python interface to web requests"""
|
|
321
321
|
|
|
322
322
|
def __init__(
|
|
@@ -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)
|
|
@@ -653,8 +653,9 @@ def mk_method_spec_from_openapi_method_spec(
|
|
|
653
653
|
|
|
654
654
|
##### Open api stuff TODO: To move ###########################################
|
|
655
655
|
from inspect import Parameter, Signature
|
|
656
|
-
from typing import Union
|
|
657
|
-
from
|
|
656
|
+
from typing import Union
|
|
657
|
+
from collections.abc import Callable, Iterable
|
|
658
|
+
from collections.abc import Mapping as MappingType
|
|
658
659
|
|
|
659
660
|
PK = Parameter.POSITIONAL_OR_KEYWORD
|
|
660
661
|
|
|
@@ -755,7 +756,8 @@ def mk_request_func_from_openapi_spec(
|
|
|
755
756
|
mk_request_function.from_openapi_spec = mk_request_func_from_openapi_spec
|
|
756
757
|
|
|
757
758
|
|
|
758
|
-
from typing import Optional,
|
|
759
|
+
from typing import Optional, Dict, Tuple
|
|
760
|
+
from collections.abc import Iterable, Callable
|
|
759
761
|
from ju.oas import Routes
|
|
760
762
|
from http2py.py2request import mk_request_func_from_openapi_spec
|
|
761
763
|
|
|
@@ -773,12 +775,12 @@ def default_path_to_func_name(method: str, uri: str) -> str:
|
|
|
773
775
|
|
|
774
776
|
def openapi_to_py(
|
|
775
777
|
openapi_spec: dict,
|
|
776
|
-
paths:
|
|
778
|
+
paths: Iterable[tuple[str, str]] | None = None,
|
|
777
779
|
*,
|
|
778
780
|
path_to_func_name: Callable[[str, str], str] = default_path_to_func_name,
|
|
779
|
-
servers:
|
|
781
|
+
servers: list | None = None,
|
|
780
782
|
default_server_url: str = "http://localhost:8000",
|
|
781
|
-
) ->
|
|
783
|
+
) -> dict[str, Callable]:
|
|
782
784
|
"""
|
|
783
785
|
Given an OpenAPI spec dict, returns a dict mapping function names to request functions.
|
|
784
786
|
The `servers` argument overrides or provides a default for the OpenAPI servers field.
|
|
@@ -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."""
|