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.
Files changed (40) hide show
  1. http2py-0.1.33/.gitattributes +1 -0
  2. http2py-0.1.33/.github/workflows/ci.yml +236 -0
  3. http2py-0.1.33/.gitignore +112 -0
  4. {http2py-0.1.30 → http2py-0.1.33}/PKG-INFO +32 -9
  5. {http2py-0.1.30 → http2py-0.1.33}/README.md +4 -2
  6. http2py-0.1.33/conftest.py +21 -0
  7. {http2py-0.1.30 → http2py-0.1.33}/http2py/api_pkg_maker.py +11 -0
  8. {http2py-0.1.30 → http2py-0.1.33}/http2py/authentication.py +8 -1
  9. {http2py-0.1.30 → http2py-0.1.33}/http2py/cli_maker.py +7 -1
  10. {http2py-0.1.30 → http2py-0.1.33}/http2py/client.py +6 -0
  11. {http2py-0.1.30 → http2py-0.1.33}/http2py/constants.py +2 -0
  12. {http2py-0.1.30 → http2py-0.1.33}/http2py/decorators.py +7 -0
  13. {http2py-0.1.30 → http2py-0.1.33}/http2py/default_configs.py +2 -0
  14. {http2py-0.1.30 → http2py-0.1.33}/http2py/example_cli.py +3 -1
  15. {http2py-0.1.30 → http2py-0.1.33}/http2py/global_state.py +2 -0
  16. {http2py-0.1.30 → http2py-0.1.33}/http2py/py2request.py +17 -15
  17. {http2py-0.1.30 → http2py-0.1.33}/http2py/testing_utils.py +6 -0
  18. http2py-0.1.33/http2py/tests/__init__.py +1 -0
  19. http2py-0.1.33/http2py/tests/conftest.py +44 -0
  20. http2py-0.1.33/http2py/tests/test_requirements.txt +1 -0
  21. {http2py-0.1.30 → http2py-0.1.33}/http2py/util.py +6 -0
  22. http2py-0.1.33/pyproject.toml +190 -0
  23. http2py-0.1.33/tests/test_ci_collection_contract.py +139 -0
  24. http2py-0.1.33/tests/test_dependency_workarounds.py +85 -0
  25. http2py-0.1.33/tests/test_smoke.py +84 -0
  26. http2py-0.1.30/http2py/tests/conftest.py +0 -30
  27. http2py-0.1.30/http2py.egg-info/PKG-INFO +0 -80
  28. http2py-0.1.30/http2py.egg-info/SOURCES.txt +0 -28
  29. http2py-0.1.30/http2py.egg-info/dependency_links.txt +0 -1
  30. http2py-0.1.30/http2py.egg-info/entry_points.txt +0 -2
  31. http2py-0.1.30/http2py.egg-info/not-zip-safe +0 -1
  32. http2py-0.1.30/http2py.egg-info/requires.txt +0 -7
  33. http2py-0.1.30/http2py.egg-info/top_level.txt +0 -1
  34. http2py-0.1.30/setup.cfg +0 -43
  35. http2py-0.1.30/setup.py +0 -3
  36. {http2py-0.1.30 → http2py-0.1.33}/LICENSE +0 -0
  37. {http2py-0.1.30 → http2py-0.1.33}/http2py/__init__.py +0 -0
  38. {http2py-0.1.30 → http2py-0.1.33}/http2py/http2py_cls.py +0 -0
  39. /http2py-0.1.30/http2py/tests/__init__.py → /http2py-0.1.33/http2py/resources/module_maker/func_tpl.txt +0 -0
  40. {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
1
+ Metadata-Version: 2.5
2
2
  Name: http2py
3
- Version: 0.1.30
3
+ Version: 0.1.33
4
4
  Summary: Tools to create python binders to http web services.
5
- Home-page: https://github.com/i2mint/http2py
6
- License: Apache
7
- Keywords: webservice,http,requests,API
8
- Platform: any
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 typing import Iterable
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 typing import Callable, Iterable
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,5 @@
1
+ """Content-type strings shared across the request and response machinery."""
2
+
1
3
  JSON_CONTENT_TYPE = "application/json"
2
4
  BINARY_CONTENT_TYPE = "application/octet-stream"
3
5
  FORM_CONTENT_TYPE = "multipart/form-data"
@@ -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,3 +1,5 @@
1
+ """Default output transformations used when a method spec does not supply one."""
2
+
1
3
  from http2py.decorators import (
2
4
  handle_raw_resp,
3
5
  handle_json_resp,
@@ -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 typing import Iterable
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
@@ -1,3 +1,5 @@
1
+ """Process-wide state (notably the shared ``requests`` session) for the clients."""
2
+
1
3
  from requests import request, Session
2
4
 
3
5
  _global_state = {}
@@ -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:{port}".format(port=DFLT_PORT)
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
- ), f"output_trans {output_trans} is not callable, try again"
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(object):
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
- arg_names
457
- ), "The query_arg_names must be a subset of the names in the url_template"
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, Callable, Iterable
657
- from typing import Mapping as MappingType
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, Iterable, Dict, Tuple, Callable
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: Optional[Iterable[Tuple[str, str]]] = None,
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: Optional[list] = None,
781
+ servers: list | None = None,
780
782
  default_server_url: str = "http://localhost:8000",
781
- ) -> Dict[str, Callable]:
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."""