ab-client-bff 0.1.0__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.
@@ -0,0 +1,212 @@
1
+ # Byte-compiled / optimized / DLL files
2
+ __pycache__/
3
+ *.py[codz]
4
+ *$py.class
5
+
6
+ # C extensions
7
+ *.so
8
+
9
+ # Distribution / packaging
10
+ .Python
11
+ build/
12
+ develop-eggs/
13
+ dist/
14
+ downloads/
15
+ eggs/
16
+ .eggs/
17
+ lib/
18
+ lib64/
19
+ parts/
20
+ sdist/
21
+ var/
22
+ wheels/
23
+ share/python-wheels/
24
+ *.egg-info/
25
+ .installed.cfg
26
+ *.egg
27
+ MANIFEST
28
+
29
+ # PyInstaller
30
+ # Usually these files are written by a python script from a template
31
+ # before PyInstaller builds the exe, so as to inject date/other infos into it.
32
+ *.manifest
33
+ *.spec
34
+
35
+ # Installer logs
36
+ pip-log.txt
37
+ pip-delete-this-directory.txt
38
+
39
+ # Unit test / coverage reports
40
+ htmlcov/
41
+ .tox/
42
+ .nox/
43
+ .coverage
44
+ .coverage.*
45
+ .cache
46
+ nosetests.xml
47
+ coverage.xml
48
+ *.cover
49
+ *.py.cover
50
+ .hypothesis/
51
+ .pytest_cache/
52
+ cover/
53
+
54
+ # Translations
55
+ *.mo
56
+ *.pot
57
+
58
+ # Django stuff:
59
+ *.log
60
+ local_settings.py
61
+ db.sqlite3
62
+ db.sqlite3-journal
63
+
64
+ # Flask stuff:
65
+ instance/
66
+ .webassets-cache
67
+
68
+ # Scrapy stuff:
69
+ .scrapy
70
+
71
+ # Sphinx documentation
72
+ docs/_build/
73
+
74
+ # PyBuilder
75
+ .pybuilder/
76
+ target/
77
+
78
+ # Jupyter Notebook
79
+ .ipynb_checkpoints
80
+
81
+ # IPython
82
+ profile_default/
83
+ ipython_config.py
84
+
85
+ # pyenv
86
+ # For a library or package, you might want to ignore these files since the code is
87
+ # intended to run in multiple environments; otherwise, check them in:
88
+ .python-version
89
+
90
+ # pipenv
91
+ # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
92
+ # However, in case of collaboration, if having platform-specific dependencies or dependencies
93
+ # having no cross-platform support, pipenv may install dependencies that don't work, or not
94
+ # install all needed dependencies.
95
+ Pipfile.lock
96
+
97
+ # UV
98
+ # Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control.
99
+ # This is especially recommended for binary packages to ensure reproducibility, and is more
100
+ # commonly ignored for libraries.
101
+ uv.lock
102
+
103
+ # poetry
104
+ # For packages, we do not commit the lock file,
105
+ # since we are not controlling the environment,
106
+ # refer to https://python-poetry.org/docs/basic-usage/#as-a-library-developer
107
+ poetry.lock
108
+ poetry.toml
109
+
110
+ # pdm
111
+ # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
112
+ # pdm recommends including project-wide configuration in pdm.toml, but excluding .pdm-python.
113
+ # https://pdm-project.org/en/latest/usage/project/#working-with-version-control
114
+ pdm.lock
115
+ pdm.toml
116
+ .pdm-python
117
+ .pdm-build/
118
+
119
+ # pixi
120
+ # Similar to Pipfile.lock, it is generally recommended to include pixi.lock in version control.
121
+ pixi.lock
122
+ # Pixi creates a virtual environment in the .pixi directory, just like venv module creates one
123
+ # in the .venv directory. It is recommended not to include this directory in version control.
124
+ .pixi
125
+
126
+ # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
127
+ __pypackages__/
128
+
129
+ # Celery stuff
130
+ celerybeat-schedule
131
+ celerybeat.pid
132
+
133
+ # SageMath parsed files
134
+ *.sage.py
135
+
136
+ # Environments
137
+ .env
138
+ .envrc
139
+ .venv
140
+ env/
141
+ venv/
142
+ ENV/
143
+ env.bak/
144
+ venv.bak/
145
+
146
+ # Spyder project settings
147
+ .spyderproject
148
+ .spyproject
149
+
150
+ # Rope project settings
151
+ .ropeproject
152
+
153
+ # mkdocs documentation
154
+ /site
155
+
156
+ # mypy
157
+ .mypy_cache/
158
+ .dmypy.json
159
+ dmypy.json
160
+
161
+ # Pyre type checker
162
+ .pyre/
163
+
164
+ # pytype static type analyzer
165
+ .pytype/
166
+
167
+ # Cython debug symbols
168
+ cython_debug/
169
+
170
+ # PyCharm
171
+ # JetBrains specific template is maintained in a separate JetBrains.gitignore that can
172
+ # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
173
+ # and can be added to the global gitignore or merged into this file. For a more nuclear
174
+ # option (not recommended) you can uncomment the following to ignore the entire idea folder.
175
+ #.idea/
176
+
177
+ # Abstra
178
+ # Abstra is an AI-powered process automation framework.
179
+ # Ignore directories containing user credentials, local state, and settings.
180
+ # Learn more at https://abstra.io/docs
181
+ .abstra/
182
+
183
+ # Visual Studio Code
184
+ # Visual Studio Code specific template is maintained in a separate VisualStudioCode.gitignore
185
+ # that can be found at https://github.com/github/gitignore/blob/main/Global/VisualStudioCode.gitignore
186
+ # and can be added to the global gitignore or merged into this file. However, if you prefer,
187
+ # you could uncomment the following to ignore the entire vscode folder
188
+ #.vscode/
189
+
190
+ # Ruff stuff:
191
+ .ruff_cache/
192
+
193
+ # PyPI configuration file
194
+ .pypirc
195
+
196
+ # Cursor
197
+ # Cursor is an AI-powered code editor. `.cursorignore` specifies files/directories to
198
+ # exclude from AI features like autocomplete and code analysis. Recommended for sensitive data
199
+ # refer to https://docs.cursor.com/context/ignore-files
200
+ .cursorignore
201
+ .cursorindexingignore
202
+
203
+ # Marimo
204
+ marimo/_static/
205
+ marimo/_lsp/
206
+ __marimo__/
207
+
208
+ # Streamlit
209
+ .streamlit/secrets.toml
210
+
211
+ # Generated Files
212
+ .DS_Store
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Matthew Coulter
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.
@@ -0,0 +1,199 @@
1
+ Metadata-Version: 2.4
2
+ Name: ab-client-bff
3
+ Version: 0.1.0
4
+ Summary: Client package for auth broker bff service.
5
+ Author-email: Matt Coulter <mattcoul7@gmail.com>
6
+ License-File: LICENSE
7
+ Requires-Python: <4.0,>=3.12
8
+ Requires-Dist: httpx<0.29.0,>=0.23.0
9
+ Requires-Dist: pydantic>=2.11.9
10
+ Description-Content-Type: text/markdown
11
+
12
+ <div align="center">
13
+
14
+ # BFF Client
15
+
16
+ The template repository for creating python packages, shared across auth-broker.
17
+
18
+ ![Python](https://img.shields.io/badge/Python-3.12-3670A0?style=for-the-badge&logo=python&logoColor=ffdd54)
19
+ ![UV](https://img.shields.io/badge/UV-Fast-6E40C9?style=for-the-badge)
20
+ ![Hatchling](https://img.shields.io/badge/Hatchling-PEP517-6E40C9?style=for-the-badge)
21
+ ![Ruff](https://img.shields.io/badge/Ruff-Lint-000000?style=for-the-badge)
22
+ ![Pre-commit](https://img.shields.io/badge/Pre--commit-Hooks-000000?style=for-the-badge)
23
+ ![Pytest](https://img.shields.io/badge/Pytest-Unit%2BAsync-08979C?style=for-the-badge)
24
+ ![Coverage](https://img.shields.io/badge/Cov-Reports-08979C?style=for-the-badge)
25
+ ![GitHub Actions](https://img.shields.io/badge/Actions-CI%2FCD-F7B500?style=for-the-badge&logo=github-actions)
26
+ ![PyPI](https://img.shields.io/badge/PyPI-Publish-6E40C9?style=for-the-badge)
27
+ ![Makefile](https://img.shields.io/badge/Makefile-Scripts-F7B500?style=for-the-badge)
28
+
29
+ 🦜🕸️
30
+
31
+ [![CI](https://github.com/auth-broker/client-template/actions/workflows/ci.yaml/badge.svg?branch=main)](https://github.com/auth-broker/client-template/actions/workflows/ci.yaml)
32
+
33
+ </div>
34
+
35
+ ______________________________________________________________________
36
+
37
+ ## Table of Contents
38
+
39
+ <!-- toc -->
40
+
41
+ - [Introduction](#introduction)
42
+ - [Quick Start](#quick-start)
43
+ - [Installation](#installation)
44
+ - [Usage](#usage)
45
+ - [Formatting and linting](#formatting-and-linting)
46
+ - [CICD](#cicd)
47
+
48
+ <!-- tocstop -->
49
+
50
+ ______________________________________________________________________
51
+
52
+ ## Introduction
53
+
54
+ This template repository aims to create a reusable package template which
55
+ streamlines the creation and publishing of isolated python packages in auth-broker.
56
+ This is aligned with the engineering vision @ auth-broker for better modularisation and
57
+ reusability of code.
58
+
59
+ ______________________________________________________________________
60
+
61
+ ## Quick Start
62
+
63
+ Since this is just a package, and not a service, there is no real "run" action.
64
+ But you can run the tests immediately.
65
+
66
+ Here are a list of available commands via make.
67
+
68
+ ### Bare Metal (i.e. your machine)
69
+
70
+ 1. `make install` - install the required dependencies.
71
+ 1. `make test` - runs the tests.
72
+
73
+ ### Docker
74
+
75
+ 1. `make build-docker` - build the docker image.
76
+ 1. `make run-docker` - run the docker compose services.
77
+ 1. `make test-docker` - run the tests in docker.
78
+ 1. `make clean-docker` - remove all docker containers etc.
79
+
80
+ ______________________________________________________________________
81
+
82
+ ## Installation
83
+
84
+ ### For Dev work on the repo
85
+
86
+ Install `uv`, (_if you haven't already_)
87
+ https://docs.astral.sh/uv/getting-started/installation/#installation-methods
88
+
89
+ ```shell
90
+ brew install uv
91
+ ```
92
+
93
+ Initialise pre-commit (validates ruff on commit.)
94
+
95
+ ```shell
96
+ uv run pre-commit install
97
+ ```
98
+
99
+ Install dependencies (including dev dependencies)
100
+
101
+ ```shell
102
+ uv sync
103
+ ```
104
+
105
+ If you are adding a new dev dependency, please run:
106
+
107
+ ```shell
108
+ uv add --dev {your-new-package}
109
+ ```
110
+
111
+ ### Namespaces
112
+
113
+ Packages all share the same namespace `ab_client`. To import this package into
114
+ your project:
115
+
116
+ ```python
117
+ from ab_client.template import placeholder_func
118
+ ```
119
+
120
+ We encourage you to make your package available to all of ab via this
121
+ `ab_client` namespace. The goal is to streamline development, POCs and overall
122
+ collaboration.
123
+
124
+ ______________________________________________________________________
125
+
126
+ ## Usage
127
+
128
+ ### Adding the dependency to your project
129
+
130
+ The library is available on PyPI. You can install it using the following
131
+ command:
132
+
133
+ **Using pip**:
134
+
135
+ ```shell
136
+ pip install your-package-name
137
+ ```
138
+
139
+ **Using UV**
140
+
141
+ Note: there is currently no nice way like poetry, hence we still needd to
142
+ provide the full url. https://github.com/astral-sh/uv/issues/10140
143
+
144
+ Add the dependency
145
+
146
+ ```shell
147
+ uv add your-package-name
148
+ ```
149
+
150
+ **Using poetry**:
151
+
152
+ Then run the following command to install the package:
153
+
154
+ ```shell
155
+ poetry add your-package-name
156
+ ```
157
+
158
+ ### How tos
159
+
160
+ **Example Usage**
161
+
162
+ ```python
163
+ # Please update this based on your package!
164
+
165
+ from ab_client.template import placeholder_func
166
+
167
+
168
+ if __name__ == "__main__":
169
+ print("This is a placeholder: ", placeholdder_func())
170
+ ```
171
+
172
+ ______________________________________________________________________
173
+
174
+ ## Formatting and linting
175
+
176
+ We use Ruff as the formatter and linter. The pre-commit has hooks which runs
177
+ checking and applies linting automatically. The CI validates the linting,
178
+ ensuring main is always looking clean.
179
+
180
+ You can manually use these commands too:
181
+
182
+ 1. `make lint` - check for linting issues.
183
+ 1. `make format` - fix linting issues.
184
+
185
+ ______________________________________________________________________
186
+
187
+ ## CICD
188
+
189
+ ### Publishing to PyPI
190
+
191
+ We publish to PyPI using Github releases. Steps are as follows:
192
+
193
+ 1. Manually update the version in `pyproject.toml` file using a PR and merge to
194
+ main. Use `uv version --bump {patch/minor/major}` to update the version.
195
+ 1. Create a new release in Github with the tag name as the version number. This
196
+ will trigger the `publish` workflow. In the Release window, type in the
197
+ version number and it will prompt to create a new tag.
198
+ 1. Verify the release in
199
+ [PyPI](https://pypi.org/project/your-package-name/)
@@ -0,0 +1,188 @@
1
+ <div align="center">
2
+
3
+ # BFF Client
4
+
5
+ The template repository for creating python packages, shared across auth-broker.
6
+
7
+ ![Python](https://img.shields.io/badge/Python-3.12-3670A0?style=for-the-badge&logo=python&logoColor=ffdd54)
8
+ ![UV](https://img.shields.io/badge/UV-Fast-6E40C9?style=for-the-badge)
9
+ ![Hatchling](https://img.shields.io/badge/Hatchling-PEP517-6E40C9?style=for-the-badge)
10
+ ![Ruff](https://img.shields.io/badge/Ruff-Lint-000000?style=for-the-badge)
11
+ ![Pre-commit](https://img.shields.io/badge/Pre--commit-Hooks-000000?style=for-the-badge)
12
+ ![Pytest](https://img.shields.io/badge/Pytest-Unit%2BAsync-08979C?style=for-the-badge)
13
+ ![Coverage](https://img.shields.io/badge/Cov-Reports-08979C?style=for-the-badge)
14
+ ![GitHub Actions](https://img.shields.io/badge/Actions-CI%2FCD-F7B500?style=for-the-badge&logo=github-actions)
15
+ ![PyPI](https://img.shields.io/badge/PyPI-Publish-6E40C9?style=for-the-badge)
16
+ ![Makefile](https://img.shields.io/badge/Makefile-Scripts-F7B500?style=for-the-badge)
17
+
18
+ 🦜🕸️
19
+
20
+ [![CI](https://github.com/auth-broker/client-template/actions/workflows/ci.yaml/badge.svg?branch=main)](https://github.com/auth-broker/client-template/actions/workflows/ci.yaml)
21
+
22
+ </div>
23
+
24
+ ______________________________________________________________________
25
+
26
+ ## Table of Contents
27
+
28
+ <!-- toc -->
29
+
30
+ - [Introduction](#introduction)
31
+ - [Quick Start](#quick-start)
32
+ - [Installation](#installation)
33
+ - [Usage](#usage)
34
+ - [Formatting and linting](#formatting-and-linting)
35
+ - [CICD](#cicd)
36
+
37
+ <!-- tocstop -->
38
+
39
+ ______________________________________________________________________
40
+
41
+ ## Introduction
42
+
43
+ This template repository aims to create a reusable package template which
44
+ streamlines the creation and publishing of isolated python packages in auth-broker.
45
+ This is aligned with the engineering vision @ auth-broker for better modularisation and
46
+ reusability of code.
47
+
48
+ ______________________________________________________________________
49
+
50
+ ## Quick Start
51
+
52
+ Since this is just a package, and not a service, there is no real "run" action.
53
+ But you can run the tests immediately.
54
+
55
+ Here are a list of available commands via make.
56
+
57
+ ### Bare Metal (i.e. your machine)
58
+
59
+ 1. `make install` - install the required dependencies.
60
+ 1. `make test` - runs the tests.
61
+
62
+ ### Docker
63
+
64
+ 1. `make build-docker` - build the docker image.
65
+ 1. `make run-docker` - run the docker compose services.
66
+ 1. `make test-docker` - run the tests in docker.
67
+ 1. `make clean-docker` - remove all docker containers etc.
68
+
69
+ ______________________________________________________________________
70
+
71
+ ## Installation
72
+
73
+ ### For Dev work on the repo
74
+
75
+ Install `uv`, (_if you haven't already_)
76
+ https://docs.astral.sh/uv/getting-started/installation/#installation-methods
77
+
78
+ ```shell
79
+ brew install uv
80
+ ```
81
+
82
+ Initialise pre-commit (validates ruff on commit.)
83
+
84
+ ```shell
85
+ uv run pre-commit install
86
+ ```
87
+
88
+ Install dependencies (including dev dependencies)
89
+
90
+ ```shell
91
+ uv sync
92
+ ```
93
+
94
+ If you are adding a new dev dependency, please run:
95
+
96
+ ```shell
97
+ uv add --dev {your-new-package}
98
+ ```
99
+
100
+ ### Namespaces
101
+
102
+ Packages all share the same namespace `ab_client`. To import this package into
103
+ your project:
104
+
105
+ ```python
106
+ from ab_client.template import placeholder_func
107
+ ```
108
+
109
+ We encourage you to make your package available to all of ab via this
110
+ `ab_client` namespace. The goal is to streamline development, POCs and overall
111
+ collaboration.
112
+
113
+ ______________________________________________________________________
114
+
115
+ ## Usage
116
+
117
+ ### Adding the dependency to your project
118
+
119
+ The library is available on PyPI. You can install it using the following
120
+ command:
121
+
122
+ **Using pip**:
123
+
124
+ ```shell
125
+ pip install your-package-name
126
+ ```
127
+
128
+ **Using UV**
129
+
130
+ Note: there is currently no nice way like poetry, hence we still needd to
131
+ provide the full url. https://github.com/astral-sh/uv/issues/10140
132
+
133
+ Add the dependency
134
+
135
+ ```shell
136
+ uv add your-package-name
137
+ ```
138
+
139
+ **Using poetry**:
140
+
141
+ Then run the following command to install the package:
142
+
143
+ ```shell
144
+ poetry add your-package-name
145
+ ```
146
+
147
+ ### How tos
148
+
149
+ **Example Usage**
150
+
151
+ ```python
152
+ # Please update this based on your package!
153
+
154
+ from ab_client.template import placeholder_func
155
+
156
+
157
+ if __name__ == "__main__":
158
+ print("This is a placeholder: ", placeholdder_func())
159
+ ```
160
+
161
+ ______________________________________________________________________
162
+
163
+ ## Formatting and linting
164
+
165
+ We use Ruff as the formatter and linter. The pre-commit has hooks which runs
166
+ checking and applies linting automatically. The CI validates the linting,
167
+ ensuring main is always looking clean.
168
+
169
+ You can manually use these commands too:
170
+
171
+ 1. `make lint` - check for linting issues.
172
+ 1. `make format` - fix linting issues.
173
+
174
+ ______________________________________________________________________
175
+
176
+ ## CICD
177
+
178
+ ### Publishing to PyPI
179
+
180
+ We publish to PyPI using Github releases. Steps are as follows:
181
+
182
+ 1. Manually update the version in `pyproject.toml` file using a PR and merge to
183
+ main. Use `uv version --bump {patch/minor/major}` to update the version.
184
+ 1. Create a new release in Github with the tag name as the version number. This
185
+ will trigger the `publish` workflow. In the Release window, type in the
186
+ version number and it will prompt to create a new tag.
187
+ 1. Verify the release in
188
+ [PyPI](https://pypi.org/project/your-package-name/)
@@ -0,0 +1,67 @@
1
+ [build-system]
2
+ build-backend = "hatchling.build"
3
+ requires = ["hatchling"]
4
+
5
+ [dependency-groups]
6
+ dev = [
7
+ "debugpy>=1.8.14,<2",
8
+ "isort>=6.0.1,<7",
9
+ "pre-commit>=4.2.0,<5",
10
+ "pytest-asyncio>=1.0.0,<2",
11
+ "pytest-cov>=6.2.1,<7",
12
+ "pytest>=8.4.1,<9",
13
+ "ruff>=0.12.3,<0.13",
14
+ "tox>=4.27.0,<5"
15
+ ]
16
+
17
+ [project]
18
+ authors = [{email = "mattcoul7@gmail.com", name = "Matt Coulter"}]
19
+ dependencies = [
20
+ "pydantic>=2.11.9",
21
+ "httpx>=0.23.0,<0.29.0",
22
+ ]
23
+ description = "Client package for auth broker bff service."
24
+ name = "ab-client-bff"
25
+ readme = "README.md"
26
+ requires-python = ">=3.12,<4.0"
27
+ version = "0.1.0"
28
+
29
+ [tool.hatch.build.targets.sdist]
30
+ include = ["src/ab_client"]
31
+
32
+ [tool.hatch.build.targets.wheel]
33
+ include = ["src/ab_client"]
34
+
35
+ [tool.hatch.build.targets.wheel.sources]
36
+ "src/ab_client" = "ab_client"
37
+
38
+ [tool.pytest.ini_options]
39
+ asyncio_default_fixture_loop_scope = "session"
40
+ asyncio_mode = "auto"
41
+ markers = [
42
+ "integration: Assigns the test to the integration test suite.",
43
+ "regression: Assigns the test to the regression test suite"
44
+ ]
45
+
46
+ [tool.ruff]
47
+ line-length = 120
48
+ src = ["src"]
49
+ target-version = "py312"
50
+
51
+ [tool.ruff.lint]
52
+ exclude = [".git", ".venv", "__pycache__", "proto"]
53
+ fixable = ["ALL"]
54
+ ignore = [
55
+ "D104" # missing docstring in public package
56
+ ]
57
+ select = [
58
+ "ARG001", # unused arguments
59
+ "B", # flake8-bugbear
60
+ "C4", # flake8-comprehensions
61
+ "D", # pydocstyle (docstring checks)
62
+ "E", # pycodestyle errors
63
+ "F", # pyflakes
64
+ "I", # isort
65
+ "UP", # pyupgrade
66
+ "W" # pycodestyle warnings
67
+ ]
@@ -0,0 +1,3 @@
1
+ from .models import *
2
+ from .clients import *
3
+ from .exceptions import *
@@ -0,0 +1,2 @@
1
+ from .sync_client import *
2
+ from .async_client import *
@@ -0,0 +1,210 @@
1
+ from __future__ import annotations
2
+
3
+ import json
4
+ from collections.abc import AsyncGenerator
5
+ from typing import Any, Dict, Optional, Union
6
+
7
+ import httpx
8
+ from pydantic import BaseModel, TypeAdapter
9
+
10
+ from ..exceptions import HTTPException
11
+ from ..models import *
12
+
13
+
14
+ class AsyncClient(BaseModel):
15
+ model_config = {"validate_assignment": True}
16
+
17
+ base_url: str = "/"
18
+ verify: Union[bool, str] = True
19
+ access_token: Optional[str] = None
20
+
21
+ async def get_access_token(self) -> Optional[str]:
22
+ return self.access_token
23
+
24
+ async def set_access_token(self, value: str) -> None:
25
+ self.access_token = value
26
+
27
+ async def login_auth_login_get(
28
+ self,
29
+ return_to: Optional[Union[str, None]] = None,
30
+ ) -> Any:
31
+ base_url = self.base_url
32
+ path = f"/auth/login"
33
+
34
+ headers = {
35
+ "Accept": "application/json",
36
+ }
37
+
38
+ _token = await self.get_access_token()
39
+ if _token:
40
+ headers["Authorization"] = f"Bearer {_token}"
41
+
42
+ query_params: Dict[str, Any] = {
43
+ "return_to": return_to,
44
+ }
45
+ query_params = {k: v for (k, v) in query_params.items() if v is not None}
46
+
47
+ async with httpx.AsyncClient(base_url=base_url, verify=self.verify) as client:
48
+ response = await client.request(
49
+ "get",
50
+ httpx.URL(path),
51
+ headers=headers,
52
+ params=query_params,
53
+ )
54
+
55
+ if response.status_code != 200:
56
+ raise HTTPException(
57
+ response.status_code,
58
+ f"login_auth_login_get failed with status code: {response.status_code}",
59
+ )
60
+
61
+ body = None if 200 == 204 else response.json()
62
+
63
+ return body
64
+
65
+ async def refresh_auth_refresh_get(
66
+ self,
67
+ return_to: Optional[Union[str, None]] = None,
68
+ refresh_token: Optional[Union[str, None]] = None,
69
+ ) -> OAuth2TokenExposed:
70
+ base_url = self.base_url
71
+ path = f"/auth/refresh"
72
+
73
+ headers = {
74
+ "Accept": "application/json",
75
+ }
76
+
77
+ _token = await self.get_access_token()
78
+ if _token:
79
+ headers["Authorization"] = f"Bearer {_token}"
80
+
81
+ query_params: Dict[str, Any] = {
82
+ "return_to": return_to,
83
+ }
84
+ query_params = {k: v for (k, v) in query_params.items() if v is not None}
85
+
86
+ async with httpx.AsyncClient(base_url=base_url, verify=self.verify) as client:
87
+ response = await client.request(
88
+ "get",
89
+ httpx.URL(path),
90
+ headers=headers,
91
+ params=query_params,
92
+ )
93
+
94
+ if response.status_code != 200:
95
+ raise HTTPException(
96
+ response.status_code,
97
+ f"refresh_auth_refresh_get failed with status code: {response.status_code}",
98
+ )
99
+
100
+ body = None if 200 == 204 else response.json()
101
+
102
+ return TypeAdapter(OAuth2TokenExposed).validate_python(body)
103
+
104
+ async def callback_auth_callback_get(self) -> OAuth2TokenExposed:
105
+ base_url = self.base_url
106
+ path = f"/auth/callback"
107
+
108
+ headers = {
109
+ "Accept": "application/json",
110
+ }
111
+
112
+ _token = await self.get_access_token()
113
+ if _token:
114
+ headers["Authorization"] = f"Bearer {_token}"
115
+
116
+ query_params: Dict[str, Any] = {}
117
+ query_params = {k: v for (k, v) in query_params.items() if v is not None}
118
+
119
+ async with httpx.AsyncClient(base_url=base_url, verify=self.verify) as client:
120
+ response = await client.request(
121
+ "get",
122
+ httpx.URL(path),
123
+ headers=headers,
124
+ params=query_params,
125
+ )
126
+
127
+ if response.status_code != 200:
128
+ raise HTTPException(
129
+ response.status_code,
130
+ f"callback_auth_callback_get failed with status code: {response.status_code}",
131
+ )
132
+
133
+ body = None if 200 == 204 else response.json()
134
+
135
+ return TypeAdapter(OAuth2TokenExposed).validate_python(body)
136
+
137
+ async def logout_auth_logout_get(
138
+ self,
139
+ return_to: Optional[Union[str, None]] = None,
140
+ ) -> Any:
141
+ base_url = self.base_url
142
+ path = f"/auth/logout"
143
+
144
+ headers = {
145
+ "Accept": "application/json",
146
+ }
147
+
148
+ _token = await self.get_access_token()
149
+ if _token:
150
+ headers["Authorization"] = f"Bearer {_token}"
151
+
152
+ query_params: Dict[str, Any] = {
153
+ "return_to": return_to,
154
+ }
155
+ query_params = {k: v for (k, v) in query_params.items() if v is not None}
156
+
157
+ async with httpx.AsyncClient(base_url=base_url, verify=self.verify) as client:
158
+ response = await client.request(
159
+ "get",
160
+ httpx.URL(path),
161
+ headers=headers,
162
+ params=query_params,
163
+ )
164
+
165
+ if response.status_code != 200:
166
+ raise HTTPException(
167
+ response.status_code,
168
+ f"logout_auth_logout_get failed with status code: {response.status_code}",
169
+ )
170
+
171
+ body = None if 200 == 204 else response.json()
172
+
173
+ return body
174
+
175
+ async def me_auth_me_get(
176
+ self,
177
+ authorization: Optional[Union[str, None]] = None,
178
+ access_token: Optional[Union[str, None]] = None,
179
+ ) -> IdentityContext:
180
+ base_url = self.base_url
181
+ path = f"/auth/me"
182
+
183
+ headers = {
184
+ "Accept": "application/json",
185
+ }
186
+
187
+ _token = await self.get_access_token()
188
+ if _token:
189
+ headers["Authorization"] = f"Bearer {_token}"
190
+
191
+ query_params: Dict[str, Any] = {}
192
+ query_params = {k: v for (k, v) in query_params.items() if v is not None}
193
+
194
+ async with httpx.AsyncClient(base_url=base_url, verify=self.verify) as client:
195
+ response = await client.request(
196
+ "get",
197
+ httpx.URL(path),
198
+ headers=headers,
199
+ params=query_params,
200
+ )
201
+
202
+ if response.status_code != 200:
203
+ raise HTTPException(
204
+ response.status_code,
205
+ f"me_auth_me_get failed with status code: {response.status_code}",
206
+ )
207
+
208
+ body = None if 200 == 204 else response.json()
209
+
210
+ return TypeAdapter(IdentityContext).validate_python(body)
@@ -0,0 +1,210 @@
1
+ from __future__ import annotations
2
+
3
+ import json
4
+ from collections.abc import Generator
5
+ from typing import Any, Dict, Optional, Union
6
+
7
+ import httpx
8
+ from pydantic import BaseModel, TypeAdapter
9
+
10
+ from ..exceptions import HTTPException
11
+ from ..models import *
12
+
13
+
14
+ class SyncClient(BaseModel):
15
+ model_config = {"validate_assignment": True}
16
+
17
+ base_url: str = "/"
18
+ verify: Union[bool, str] = True
19
+ access_token: Optional[str] = None
20
+
21
+ def get_access_token(self) -> Optional[str]:
22
+ return self.access_token
23
+
24
+ def set_access_token(self, value: str) -> None:
25
+ self.access_token = value
26
+
27
+ def login_auth_login_get(
28
+ self,
29
+ return_to: Optional[Union[str, None]] = None,
30
+ ) -> Any:
31
+ base_url = self.base_url
32
+ path = f"/auth/login"
33
+
34
+ headers = {
35
+ "Accept": "application/json",
36
+ }
37
+
38
+ _token = self.get_access_token()
39
+ if _token:
40
+ headers["Authorization"] = f"Bearer {_token}"
41
+
42
+ query_params: Dict[str, Any] = {
43
+ "return_to": return_to,
44
+ }
45
+ query_params = {k: v for (k, v) in query_params.items() if v is not None}
46
+
47
+ with httpx.Client(base_url=base_url, verify=self.verify) as client:
48
+ response = client.request(
49
+ "get",
50
+ httpx.URL(path),
51
+ headers=headers,
52
+ params=query_params,
53
+ )
54
+
55
+ if response.status_code != 200:
56
+ raise HTTPException(
57
+ response.status_code,
58
+ f"login_auth_login_get failed with status code: {response.status_code}",
59
+ )
60
+
61
+ body = None if 200 == 204 else response.json()
62
+
63
+ return body
64
+
65
+ def refresh_auth_refresh_get(
66
+ self,
67
+ return_to: Optional[Union[str, None]] = None,
68
+ refresh_token: Optional[Union[str, None]] = None,
69
+ ) -> OAuth2TokenExposed:
70
+ base_url = self.base_url
71
+ path = f"/auth/refresh"
72
+
73
+ headers = {
74
+ "Accept": "application/json",
75
+ }
76
+
77
+ _token = self.get_access_token()
78
+ if _token:
79
+ headers["Authorization"] = f"Bearer {_token}"
80
+
81
+ query_params: Dict[str, Any] = {
82
+ "return_to": return_to,
83
+ }
84
+ query_params = {k: v for (k, v) in query_params.items() if v is not None}
85
+
86
+ with httpx.Client(base_url=base_url, verify=self.verify) as client:
87
+ response = client.request(
88
+ "get",
89
+ httpx.URL(path),
90
+ headers=headers,
91
+ params=query_params,
92
+ )
93
+
94
+ if response.status_code != 200:
95
+ raise HTTPException(
96
+ response.status_code,
97
+ f"refresh_auth_refresh_get failed with status code: {response.status_code}",
98
+ )
99
+
100
+ body = None if 200 == 204 else response.json()
101
+
102
+ return TypeAdapter(OAuth2TokenExposed).validate_python(body)
103
+
104
+ def callback_auth_callback_get(self) -> OAuth2TokenExposed:
105
+ base_url = self.base_url
106
+ path = f"/auth/callback"
107
+
108
+ headers = {
109
+ "Accept": "application/json",
110
+ }
111
+
112
+ _token = self.get_access_token()
113
+ if _token:
114
+ headers["Authorization"] = f"Bearer {_token}"
115
+
116
+ query_params: Dict[str, Any] = {}
117
+ query_params = {k: v for (k, v) in query_params.items() if v is not None}
118
+
119
+ with httpx.Client(base_url=base_url, verify=self.verify) as client:
120
+ response = client.request(
121
+ "get",
122
+ httpx.URL(path),
123
+ headers=headers,
124
+ params=query_params,
125
+ )
126
+
127
+ if response.status_code != 200:
128
+ raise HTTPException(
129
+ response.status_code,
130
+ f"callback_auth_callback_get failed with status code: {response.status_code}",
131
+ )
132
+
133
+ body = None if 200 == 204 else response.json()
134
+
135
+ return TypeAdapter(OAuth2TokenExposed).validate_python(body)
136
+
137
+ def logout_auth_logout_get(
138
+ self,
139
+ return_to: Optional[Union[str, None]] = None,
140
+ ) -> Any:
141
+ base_url = self.base_url
142
+ path = f"/auth/logout"
143
+
144
+ headers = {
145
+ "Accept": "application/json",
146
+ }
147
+
148
+ _token = self.get_access_token()
149
+ if _token:
150
+ headers["Authorization"] = f"Bearer {_token}"
151
+
152
+ query_params: Dict[str, Any] = {
153
+ "return_to": return_to,
154
+ }
155
+ query_params = {k: v for (k, v) in query_params.items() if v is not None}
156
+
157
+ with httpx.Client(base_url=base_url, verify=self.verify) as client:
158
+ response = client.request(
159
+ "get",
160
+ httpx.URL(path),
161
+ headers=headers,
162
+ params=query_params,
163
+ )
164
+
165
+ if response.status_code != 200:
166
+ raise HTTPException(
167
+ response.status_code,
168
+ f"logout_auth_logout_get failed with status code: {response.status_code}",
169
+ )
170
+
171
+ body = None if 200 == 204 else response.json()
172
+
173
+ return body
174
+
175
+ def me_auth_me_get(
176
+ self,
177
+ authorization: Optional[Union[str, None]] = None,
178
+ access_token: Optional[Union[str, None]] = None,
179
+ ) -> IdentityContext:
180
+ base_url = self.base_url
181
+ path = f"/auth/me"
182
+
183
+ headers = {
184
+ "Accept": "application/json",
185
+ }
186
+
187
+ _token = self.get_access_token()
188
+ if _token:
189
+ headers["Authorization"] = f"Bearer {_token}"
190
+
191
+ query_params: Dict[str, Any] = {}
192
+ query_params = {k: v for (k, v) in query_params.items() if v is not None}
193
+
194
+ with httpx.Client(base_url=base_url, verify=self.verify) as client:
195
+ response = client.request(
196
+ "get",
197
+ httpx.URL(path),
198
+ headers=headers,
199
+ params=query_params,
200
+ )
201
+
202
+ if response.status_code != 200:
203
+ raise HTTPException(
204
+ response.status_code,
205
+ f"me_auth_me_get failed with status code: {response.status_code}",
206
+ )
207
+
208
+ body = None if 200 == 204 else response.json()
209
+
210
+ return TypeAdapter(IdentityContext).validate_python(body)
@@ -0,0 +1 @@
1
+ from .http_exception import *
@@ -0,0 +1,8 @@
1
+ class HTTPException(Exception):
2
+ def __init__(self, status_code: int, message: str):
3
+ self.status_code = status_code
4
+ self.message = message
5
+ super().__init__(f"{status_code} {message}")
6
+
7
+ def __str__(self) -> str:
8
+ return f"{self.status_code} {self.message}"
@@ -0,0 +1,15 @@
1
+ from typing import *
2
+
3
+ from pydantic import BaseModel, Field
4
+
5
+ from .ValidationError import ValidationError
6
+
7
+
8
+ class HTTPValidationError(BaseModel):
9
+ """
10
+ HTTPValidationError model
11
+ """
12
+
13
+ model_config = {"populate_by_name": True, "validate_assignment": True}
14
+
15
+ detail: Optional[List[Optional[ValidationError]]] = Field(validation_alias="detail", default=None)
@@ -0,0 +1,21 @@
1
+ from typing import *
2
+
3
+ from pydantic import BaseModel, Field
4
+
5
+ from .User import User
6
+ from .ValidatedOIDCClaims import ValidatedOIDCClaims
7
+
8
+
9
+ class IdentityContext(BaseModel):
10
+ """
11
+ IdentityContext model
12
+ Per-request identity context resolved from the bearer token.
13
+ """
14
+
15
+ model_config = {"populate_by_name": True, "validate_assignment": True}
16
+
17
+ token: str = Field(validation_alias="token")
18
+
19
+ claims: ValidatedOIDCClaims = Field(validation_alias="claims")
20
+
21
+ user: User = Field(validation_alias="user")
@@ -0,0 +1,21 @@
1
+ from typing import *
2
+
3
+ from pydantic import BaseModel, Field
4
+
5
+
6
+ class OAuth2TokenExposed(BaseModel):
7
+ """
8
+ OAuth2TokenExposed model
9
+ OAuth2TokenExposed model
10
+ An OAuth2 token model with secrets exposed as plain strings.
11
+ """
12
+
13
+ model_config = {"populate_by_name": True, "validate_assignment": True}
14
+
15
+ access_token: str = Field(validation_alias="access_token")
16
+
17
+ id_token: Optional[Union[str, None]] = Field(validation_alias="id_token", default=None)
18
+
19
+ refresh_token: Optional[Union[str, None]] = Field(validation_alias="refresh_token", default=None)
20
+
21
+ app_context: Optional[Union[Dict[str, str], None]] = Field(validation_alias="app_context", default=None)
@@ -0,0 +1,33 @@
1
+ from typing import *
2
+
3
+ from pydantic import BaseModel, Field
4
+
5
+
6
+ class User(BaseModel):
7
+ """
8
+ User model
9
+ User model
10
+ User model.
11
+ """
12
+
13
+ model_config = {"populate_by_name": True, "validate_assignment": True}
14
+
15
+ is_active: Optional[Union[bool, None]] = Field(validation_alias="is_active", default=True)
16
+
17
+ updated_at: str = Field(validation_alias="updated_at")
18
+
19
+ created_at: str = Field(validation_alias="created_at")
20
+
21
+ id: Optional[Union[str, None]] = Field(validation_alias="id", default=None)
22
+
23
+ oidc_sub: str = Field(validation_alias="oidc_sub")
24
+
25
+ oidc_iss: str = Field(validation_alias="oidc_iss")
26
+
27
+ email: Optional[Union[str, None]] = Field(validation_alias="email", default=None)
28
+
29
+ display_name: Optional[Union[str, None]] = Field(validation_alias="display_name", default=None)
30
+
31
+ preferred_username: Optional[Union[str, None]] = Field(validation_alias="preferred_username", default=None)
32
+
33
+ last_seen: Union[str, None] = Field(validation_alias="last_seen")
@@ -0,0 +1,40 @@
1
+ from typing import *
2
+
3
+ from pydantic import BaseModel, Field
4
+
5
+
6
+ class ValidatedOIDCClaims(BaseModel):
7
+ """
8
+ ValidatedOIDCClaims model
9
+ ValidatedOIDCClaims model
10
+ """
11
+
12
+ model_config = {"populate_by_name": True, "validate_assignment": True}
13
+
14
+ iss: str = Field(validation_alias="iss")
15
+
16
+ sub: str = Field(validation_alias="sub")
17
+
18
+ aud: Union[str, List[str]] = Field(validation_alias="aud")
19
+
20
+ exp: int = Field(validation_alias="exp")
21
+
22
+ iat: int = Field(validation_alias="iat")
23
+
24
+ auth_time: int = Field(validation_alias="auth_time")
25
+
26
+ acr: str = Field(validation_alias="acr")
27
+
28
+ email: Optional[Union[str, None]] = Field(validation_alias="email", default=None)
29
+
30
+ email_verified: Optional[Union[bool, None]] = Field(validation_alias="email_verified", default=None)
31
+
32
+ name: Optional[Union[str, None]] = Field(validation_alias="name", default=None)
33
+
34
+ given_name: Optional[Union[str, None]] = Field(validation_alias="given_name", default=None)
35
+
36
+ preferred_username: Optional[Union[str, None]] = Field(validation_alias="preferred_username", default=None)
37
+
38
+ nickname: Optional[Union[str, None]] = Field(validation_alias="nickname", default=None)
39
+
40
+ groups: Optional[Union[List[str], None]] = Field(validation_alias="groups", default=None)
@@ -0,0 +1,17 @@
1
+ from typing import *
2
+
3
+ from pydantic import BaseModel, Field
4
+
5
+
6
+ class ValidationError(BaseModel):
7
+ """
8
+ ValidationError model
9
+ """
10
+
11
+ model_config = {"populate_by_name": True, "validate_assignment": True}
12
+
13
+ loc: List[Union[str, int]] = Field(validation_alias="loc")
14
+
15
+ msg: str = Field(validation_alias="msg")
16
+
17
+ type: str = Field(validation_alias="type")
@@ -0,0 +1,6 @@
1
+ from .HTTPValidationError import *
2
+ from .IdentityContext import *
3
+ from .OAuth2TokenExposed import *
4
+ from .User import *
5
+ from .ValidatedOIDCClaims import *
6
+ from .ValidationError import *