bling-jwt-auth 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.
Files changed (33) hide show
  1. bling_jwt_auth-0.1.0/.gitignore +20 -0
  2. bling_jwt_auth-0.1.0/LICENSE +21 -0
  3. bling_jwt_auth-0.1.0/PKG-INFO +176 -0
  4. bling_jwt_auth-0.1.0/README.md +144 -0
  5. bling_jwt_auth-0.1.0/examples/__init__.py +1 -0
  6. bling_jwt_auth-0.1.0/examples/authenticated_request.py +91 -0
  7. bling_jwt_auth-0.1.0/examples/oauth_flow.py +43 -0
  8. bling_jwt_auth-0.1.0/pyproject.toml +129 -0
  9. bling_jwt_auth-0.1.0/scripts/check.sh +34 -0
  10. bling_jwt_auth-0.1.0/src/bling_jwt_auth/__init__.py +31 -0
  11. bling_jwt_auth-0.1.0/src/bling_jwt_auth/config.py +59 -0
  12. bling_jwt_auth-0.1.0/src/bling_jwt_auth/constants.py +14 -0
  13. bling_jwt_auth-0.1.0/src/bling_jwt_auth/exceptions.py +25 -0
  14. bling_jwt_auth-0.1.0/src/bling_jwt_auth/headers.py +13 -0
  15. bling_jwt_auth-0.1.0/src/bling_jwt_auth/manager.py +55 -0
  16. bling_jwt_auth-0.1.0/src/bling_jwt_auth/models/__init__.py +5 -0
  17. bling_jwt_auth-0.1.0/src/bling_jwt_auth/models/token.py +69 -0
  18. bling_jwt_auth-0.1.0/src/bling_jwt_auth/oauth/__init__.py +5 -0
  19. bling_jwt_auth-0.1.0/src/bling_jwt_auth/oauth/client.py +148 -0
  20. bling_jwt_auth-0.1.0/src/bling_jwt_auth/storage/__init__.py +8 -0
  21. bling_jwt_auth-0.1.0/src/bling_jwt_auth/storage/base.py +22 -0
  22. bling_jwt_auth-0.1.0/src/bling_jwt_auth/storage/factory.py +20 -0
  23. bling_jwt_auth-0.1.0/src/bling_jwt_auth/storage/file.py +62 -0
  24. bling_jwt_auth-0.1.0/src/bling_jwt_auth/storage/sqlite.py +82 -0
  25. bling_jwt_auth-0.1.0/tests/__init__.py +1 -0
  26. bling_jwt_auth-0.1.0/tests/conftest.py +35 -0
  27. bling_jwt_auth-0.1.0/tests/test_headers.py +11 -0
  28. bling_jwt_auth-0.1.0/tests/test_oauth_client.py +151 -0
  29. bling_jwt_auth-0.1.0/tests/test_storage_factory.py +68 -0
  30. bling_jwt_auth-0.1.0/tests/test_storage_file.py +51 -0
  31. bling_jwt_auth-0.1.0/tests/test_storage_sqlite.py +43 -0
  32. bling_jwt_auth-0.1.0/tests/test_token_manager.py +130 -0
  33. bling_jwt_auth-0.1.0/tests/url_utils.py +12 -0
@@ -0,0 +1,20 @@
1
+ # Python-generated files
2
+ __pycache__/
3
+ *.py[oc]
4
+ build/
5
+ dist/
6
+ wheels/
7
+ *.egg-info
8
+
9
+ # Virtual environments
10
+ .venv
11
+
12
+ # Testing / tooling
13
+ .pytest_cache/
14
+ .ruff_cache/
15
+
16
+ # Local secrets and token files
17
+ .env
18
+ .env.*
19
+ *.db
20
+ token.json
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Mercanatu contributors
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,176 @@
1
+ Metadata-Version: 2.4
2
+ Name: bling-jwt-auth
3
+ Version: 0.1.0
4
+ Summary: OAuth 2.0 / JWT authentication helpers for the Bling API v3
5
+ Project-URL: Homepage, https://github.com/tempont/bling-jwt-auth-python
6
+ Project-URL: Documentation, https://github.com/tempont/bling-jwt-auth-python#readme
7
+ Project-URL: Repository, https://github.com/tempont/bling-jwt-auth-python
8
+ Project-URL: Issues, https://github.com/tempont/bling-jwt-auth-python/issues
9
+ Author: tempont
10
+ License-Expression: MIT
11
+ License-File: LICENSE
12
+ Keywords: api,authentication,bling,erp,jwt,oauth2
13
+ Classifier: Development Status :: 3 - Alpha
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: License :: OSI Approved :: MIT License
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Programming Language :: Python :: 3 :: Only
18
+ Classifier: Programming Language :: Python :: 3.14
19
+ Classifier: Typing :: Typed
20
+ Requires-Python: >=3.14
21
+ Requires-Dist: httpx>=0.28.0
22
+ Requires-Dist: pydantic-settings>=2.0.0
23
+ Requires-Dist: pydantic>=2.0.0
24
+ Requires-Dist: python-dotenv>=1.0.0
25
+ Provides-Extra: dev
26
+ Requires-Dist: basedpyright>=1.0.0; extra == 'dev'
27
+ Requires-Dist: pre-commit>=4.0.0; extra == 'dev'
28
+ Requires-Dist: pytest-httpx>=0.30.0; extra == 'dev'
29
+ Requires-Dist: pytest>=8.0.0; extra == 'dev'
30
+ Requires-Dist: ruff>=0.8.0; extra == 'dev'
31
+ Description-Content-Type: text/markdown
32
+
33
+ # bling-jwt-auth-python
34
+
35
+ Repositório: [github.com/tempont/bling-jwt-auth-python](https://github.com/tempont/bling-jwt-auth-python) · PyPI: [`bling-jwt-auth`](https://pypi.org/project/bling-jwt-auth/)
36
+
37
+ Biblioteca Python simples para autenticar na **API v3 do Bling** usando OAuth 2.0 e tokens JWT.
38
+
39
+ Ela ajuda a:
40
+
41
+ - gerar a URL de autorização do Bling;
42
+ - trocar o `code` recebido por tokens;
43
+ - salvar os tokens em arquivo ou SQLite;
44
+ - renovar o access token automaticamente quando necessário;
45
+ - montar os headers corretos para chamar a API do Bling.
46
+
47
+ Versão em inglês: [docs/README.en.md](docs/README.en.md)
48
+
49
+ ## Requisitos
50
+
51
+ - Python 3.14 ou superior
52
+ - Uma aplicação OAuth cadastrada no Bling
53
+
54
+ ## Instalação
55
+
56
+ Instale pelo `pip`:
57
+
58
+ ```bash
59
+ pip install bling-jwt-auth
60
+ ```
61
+
62
+ Ou instale direto do GitHub:
63
+
64
+ ```bash
65
+ pip install "git+https://github.com/tempont/bling-jwt-auth-python.git"
66
+ ```
67
+
68
+ Para desenvolvimento local neste repositório, use:
69
+
70
+ ```bash
71
+ uv sync --extra dev
72
+ ```
73
+
74
+ ## Configuração
75
+
76
+ Copie o arquivo de exemplo:
77
+
78
+ ```bash
79
+ cp .env.example .env
80
+ ```
81
+
82
+ Edite o `.env` com os dados da sua aplicação no Bling:
83
+
84
+ ```env
85
+ BLING_CLIENT_ID=seu_client_id
86
+ BLING_CLIENT_SECRET=seu_client_secret
87
+ BLING_REDIRECT_URI=https://seu-dominio.com/oauth/callback
88
+ ```
89
+
90
+ Por padrão, os tokens são salvos em SQLite. Se quiser salvar em JSON:
91
+
92
+ ```env
93
+ BLING_TOKEN_STORE=file
94
+ BLING_TOKEN_STORE_PATH=./token.json
95
+ ```
96
+
97
+ ## Como usar
98
+
99
+ ### 1. Autorizar a conta Bling
100
+
101
+ Rode o exemplo de OAuth:
102
+
103
+ ```bash
104
+ uv run python examples/oauth_flow.py
105
+ ```
106
+
107
+ O script vai mostrar uma URL. Abra essa URL no navegador, autorize o acesso no Bling e cole no terminal o `code` recebido no callback.
108
+
109
+ Se quiser que o script tente abrir o navegador automaticamente:
110
+
111
+ ```bash
112
+ uv run python examples/oauth_flow.py --open
113
+ ```
114
+
115
+ ### 2. Testar uma chamada autenticada
116
+
117
+ Depois de salvar o token, rode:
118
+
119
+ ```bash
120
+ uv run python examples/authenticated_request.py
121
+ ```
122
+
123
+ Esse exemplo usa o token salvo, renova se necessário e chama um endpoint de homologação do Bling.
124
+
125
+ ### 3. Usar no seu código
126
+
127
+ ```python
128
+ import httpx
129
+ from bling_jwt_auth import (
130
+ BlingAuthSettings,
131
+ OAuthClient,
132
+ TokenManager,
133
+ bling_api_headers,
134
+ create_token_store,
135
+ )
136
+
137
+ settings = BlingAuthSettings()
138
+ store = create_token_store(settings)
139
+
140
+ with OAuthClient(settings) as oauth:
141
+ manager = TokenManager(oauth, store, settings)
142
+ access_token = manager.get_access_token()
143
+
144
+ headers = bling_api_headers(access_token)
145
+
146
+ response = httpx.get(
147
+ "https://api.bling.com.br/Api/v3/produtos",
148
+ headers=headers,
149
+ )
150
+ response.raise_for_status()
151
+ print(response.json())
152
+ ```
153
+
154
+ ## Comandos úteis para desenvolvimento
155
+
156
+ Rodar lint, checagem de tipos e testes:
157
+
158
+ ```bash
159
+ make check
160
+ ```
161
+
162
+ Ou:
163
+
164
+ ```bash
165
+ bash scripts/check.sh
166
+ ```
167
+
168
+ Rodar apenas os testes:
169
+
170
+ ```bash
171
+ uv run --extra dev pytest
172
+ ```
173
+
174
+ ## Licença
175
+
176
+ MIT. Veja [LICENSE](LICENSE).
@@ -0,0 +1,144 @@
1
+ # bling-jwt-auth-python
2
+
3
+ Repositório: [github.com/tempont/bling-jwt-auth-python](https://github.com/tempont/bling-jwt-auth-python) · PyPI: [`bling-jwt-auth`](https://pypi.org/project/bling-jwt-auth/)
4
+
5
+ Biblioteca Python simples para autenticar na **API v3 do Bling** usando OAuth 2.0 e tokens JWT.
6
+
7
+ Ela ajuda a:
8
+
9
+ - gerar a URL de autorização do Bling;
10
+ - trocar o `code` recebido por tokens;
11
+ - salvar os tokens em arquivo ou SQLite;
12
+ - renovar o access token automaticamente quando necessário;
13
+ - montar os headers corretos para chamar a API do Bling.
14
+
15
+ Versão em inglês: [docs/README.en.md](docs/README.en.md)
16
+
17
+ ## Requisitos
18
+
19
+ - Python 3.14 ou superior
20
+ - Uma aplicação OAuth cadastrada no Bling
21
+
22
+ ## Instalação
23
+
24
+ Instale pelo `pip`:
25
+
26
+ ```bash
27
+ pip install bling-jwt-auth
28
+ ```
29
+
30
+ Ou instale direto do GitHub:
31
+
32
+ ```bash
33
+ pip install "git+https://github.com/tempont/bling-jwt-auth-python.git"
34
+ ```
35
+
36
+ Para desenvolvimento local neste repositório, use:
37
+
38
+ ```bash
39
+ uv sync --extra dev
40
+ ```
41
+
42
+ ## Configuração
43
+
44
+ Copie o arquivo de exemplo:
45
+
46
+ ```bash
47
+ cp .env.example .env
48
+ ```
49
+
50
+ Edite o `.env` com os dados da sua aplicação no Bling:
51
+
52
+ ```env
53
+ BLING_CLIENT_ID=seu_client_id
54
+ BLING_CLIENT_SECRET=seu_client_secret
55
+ BLING_REDIRECT_URI=https://seu-dominio.com/oauth/callback
56
+ ```
57
+
58
+ Por padrão, os tokens são salvos em SQLite. Se quiser salvar em JSON:
59
+
60
+ ```env
61
+ BLING_TOKEN_STORE=file
62
+ BLING_TOKEN_STORE_PATH=./token.json
63
+ ```
64
+
65
+ ## Como usar
66
+
67
+ ### 1. Autorizar a conta Bling
68
+
69
+ Rode o exemplo de OAuth:
70
+
71
+ ```bash
72
+ uv run python examples/oauth_flow.py
73
+ ```
74
+
75
+ O script vai mostrar uma URL. Abra essa URL no navegador, autorize o acesso no Bling e cole no terminal o `code` recebido no callback.
76
+
77
+ Se quiser que o script tente abrir o navegador automaticamente:
78
+
79
+ ```bash
80
+ uv run python examples/oauth_flow.py --open
81
+ ```
82
+
83
+ ### 2. Testar uma chamada autenticada
84
+
85
+ Depois de salvar o token, rode:
86
+
87
+ ```bash
88
+ uv run python examples/authenticated_request.py
89
+ ```
90
+
91
+ Esse exemplo usa o token salvo, renova se necessário e chama um endpoint de homologação do Bling.
92
+
93
+ ### 3. Usar no seu código
94
+
95
+ ```python
96
+ import httpx
97
+ from bling_jwt_auth import (
98
+ BlingAuthSettings,
99
+ OAuthClient,
100
+ TokenManager,
101
+ bling_api_headers,
102
+ create_token_store,
103
+ )
104
+
105
+ settings = BlingAuthSettings()
106
+ store = create_token_store(settings)
107
+
108
+ with OAuthClient(settings) as oauth:
109
+ manager = TokenManager(oauth, store, settings)
110
+ access_token = manager.get_access_token()
111
+
112
+ headers = bling_api_headers(access_token)
113
+
114
+ response = httpx.get(
115
+ "https://api.bling.com.br/Api/v3/produtos",
116
+ headers=headers,
117
+ )
118
+ response.raise_for_status()
119
+ print(response.json())
120
+ ```
121
+
122
+ ## Comandos úteis para desenvolvimento
123
+
124
+ Rodar lint, checagem de tipos e testes:
125
+
126
+ ```bash
127
+ make check
128
+ ```
129
+
130
+ Ou:
131
+
132
+ ```bash
133
+ bash scripts/check.sh
134
+ ```
135
+
136
+ Rodar apenas os testes:
137
+
138
+ ```bash
139
+ uv run --extra dev pytest
140
+ ```
141
+
142
+ ## Licença
143
+
144
+ MIT. Veja [LICENSE](LICENSE).
@@ -0,0 +1 @@
1
+ """Example scripts."""
@@ -0,0 +1,91 @@
1
+ """Call the Bling homologation endpoint to verify OAuth + stored tokens.
2
+
3
+ Loads secrets from `./.env` (see `env_file` on `BlingAuthSettings`) and/or exported
4
+ `BLING_*` environment variables — run from the repo root next to `.env`.
5
+
6
+ Uses the same token store as `oauth_flow.py` (see `BLING_TOKEN_STORE` and
7
+ `BLING_TOKEN_STORE_PATH`).
8
+
9
+ Example:
10
+ uv sync
11
+ uv run python examples/oauth_flow.py
12
+ uv run python examples/authenticated_request.py
13
+ """
14
+
15
+ from __future__ import annotations
16
+
17
+ import json
18
+ import sys
19
+ from typing import Any, cast
20
+
21
+ import httpx
22
+
23
+ from bling_jwt_auth import (
24
+ BlingAuthSettings,
25
+ OAuthClient,
26
+ TokenManager,
27
+ TokenNotFoundError,
28
+ bling_api_headers,
29
+ create_token_store,
30
+ )
31
+
32
+ HOMOLOGACAO_PRODUTOS_URL = "https://api.bling.com.br/Api/v3/homologacao/produtos"
33
+
34
+
35
+ def _summarize_body(text: str, *, max_len: int = 800) -> str:
36
+ if len(text) <= max_len:
37
+ return text
38
+ return text[: max_len - 3] + "..."
39
+
40
+
41
+ def main() -> None:
42
+ """GET homologação produtos using the access token from the configured store."""
43
+ settings = BlingAuthSettings.load()
44
+ store = create_token_store(settings)
45
+ print(f"Token store: {settings.token_store.value} at {store.path}")
46
+
47
+ with OAuthClient(settings) as oauth:
48
+ manager = TokenManager(oauth, store, settings)
49
+ try:
50
+ access_token = manager.get_access_token()
51
+ except TokenNotFoundError:
52
+ print(
53
+ "No token found. Run `uv run python examples/oauth_flow.py` first "
54
+ f"using the same BLING_TOKEN_STORE ({settings.token_store.value}).",
55
+ file=sys.stderr,
56
+ )
57
+ sys.exit(1)
58
+
59
+ headers = bling_api_headers(access_token)
60
+ with httpx.Client(timeout=30.0) as client:
61
+ response = client.get(HOMOLOGACAO_PRODUTOS_URL, headers=headers)
62
+
63
+ if not response.is_success:
64
+ print(
65
+ f"Request failed: HTTP {response.status_code}\n"
66
+ f"{_summarize_body(response.text)}",
67
+ file=sys.stderr,
68
+ )
69
+ sys.exit(1)
70
+
71
+ try:
72
+ parsed: Any = response.json()
73
+ except json.JSONDecodeError:
74
+ print("Unexpected response: not JSON", file=sys.stderr)
75
+ print(_summarize_body(response.text), file=sys.stderr)
76
+ sys.exit(1)
77
+
78
+ if not isinstance(parsed, dict):
79
+ print("Unexpected response: JSON must be an object", file=sys.stderr)
80
+ sys.exit(1)
81
+ body: dict[str, Any] = cast("dict[str, Any]", parsed)
82
+ data: Any | None = body.get("data")
83
+ preview_payload: Any = body if data is None else data
84
+ preview = json.dumps(preview_payload, indent=2, ensure_ascii=False)
85
+ print(f"HTTP {response.status_code} OK")
86
+ print(preview)
87
+ print("Token from store is valid for the Bling API (homologação GET).")
88
+
89
+
90
+ if __name__ == "__main__":
91
+ main()
@@ -0,0 +1,43 @@
1
+ """Minimal manual OAuth walkthrough.
2
+
3
+ Loads secrets from `./.env` (see `env_file` on `BlingAuthSettings`) and/or exported
4
+ `BLING_*` environment variables — run from the repo root next to `.env`.
5
+
6
+ Example:
7
+ uv sync
8
+ uv run python examples/oauth_flow.py
9
+ """
10
+
11
+ from __future__ import annotations
12
+
13
+ import os
14
+ import sys
15
+ import webbrowser
16
+
17
+ from bling_jwt_auth import BlingAuthSettings, OAuthClient, TokenManager, create_token_store
18
+
19
+
20
+ def main() -> None:
21
+ """Prompt for OAuth code interactively after printing the authorize URL."""
22
+ settings = BlingAuthSettings.load()
23
+ store = create_token_store(settings)
24
+ with OAuthClient(settings) as oauth:
25
+ manager = TokenManager(oauth, store, settings)
26
+
27
+ auth_url = oauth.build_authorization_url(state=os.urandom(16).hex())
28
+ print("Open this URL in a browser, approve access, then copy the `code` query param:")
29
+ print(auth_url)
30
+ if "--open" in sys.argv:
31
+ webbrowser.open(auth_url)
32
+
33
+ code = input("Paste authorization code: ").strip()
34
+ manager.save_from_code(code)
35
+ token = manager.get_access_token()
36
+ print("Access token acquired (truncated):", token[:24], "...")
37
+ print("Use HTTP headers:")
38
+ print(" Authorization: Bearer", "<token>")
39
+ print(" enable-jwt: 1")
40
+
41
+
42
+ if __name__ == "__main__":
43
+ main()
@@ -0,0 +1,129 @@
1
+ [build-system]
2
+ requires = ["hatchling>=1.24"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "bling-jwt-auth"
7
+ version = "0.1.0"
8
+ description = "OAuth 2.0 / JWT authentication helpers for the Bling API v3"
9
+ readme = "README.md"
10
+ license = "MIT"
11
+ requires-python = ">=3.14"
12
+ authors = [{ name = "tempont" }]
13
+ keywords = ["bling", "oauth2", "jwt", "authentication", "erp", "api"]
14
+ classifiers = [
15
+ "Development Status :: 3 - Alpha",
16
+ "Intended Audience :: Developers",
17
+ "License :: OSI Approved :: MIT License",
18
+ "Programming Language :: Python :: 3",
19
+ "Programming Language :: Python :: 3 :: Only",
20
+ "Programming Language :: Python :: 3.14",
21
+ "Typing :: Typed",
22
+ ]
23
+ dependencies = [
24
+ "httpx>=0.28.0",
25
+ "pydantic>=2.0.0",
26
+ "pydantic-settings>=2.0.0",
27
+ "python-dotenv>=1.0.0",
28
+ ]
29
+
30
+ [project.urls]
31
+ Homepage = "https://github.com/tempont/bling-jwt-auth-python"
32
+ Documentation = "https://github.com/tempont/bling-jwt-auth-python#readme"
33
+ Repository = "https://github.com/tempont/bling-jwt-auth-python"
34
+ Issues = "https://github.com/tempont/bling-jwt-auth-python/issues"
35
+
36
+ [project.optional-dependencies]
37
+ dev = [
38
+ "basedpyright>=1.0.0",
39
+ "pre-commit>=4.0.0",
40
+ "pytest>=8.0.0",
41
+ "pytest-httpx>=0.30.0",
42
+ "ruff>=0.8.0",
43
+ ]
44
+
45
+ [tool.hatch.build.targets.wheel]
46
+ packages = ["src/bling_jwt_auth"]
47
+
48
+ [tool.hatch.build.targets.sdist]
49
+ include = [
50
+ "/scripts",
51
+ "/src",
52
+ "/tests",
53
+ "/examples",
54
+ "/README.md",
55
+ "/LICENSE",
56
+ ]
57
+
58
+ [tool.pytest.ini_options]
59
+ testpaths = ["tests"]
60
+
61
+ [tool.ruff]
62
+ target-version = "py314"
63
+ line-length = 100
64
+ indent-width = 4
65
+ exclude = [".git", ".ruff_cache", ".venv"]
66
+ show-fixes = true
67
+
68
+ [tool.ruff.format]
69
+ indent-style = "space"
70
+ line-ending = "lf"
71
+ quote-style = "double"
72
+ docstring-code-format = true
73
+
74
+ [tool.ruff.lint]
75
+ select = ["ALL"]
76
+ ignore = [
77
+ "YTT",
78
+ "CPY",
79
+ "FA",
80
+ "TD",
81
+ "C90",
82
+ "PGH",
83
+ "COM812",
84
+ "COM819",
85
+ "D206",
86
+ "D300",
87
+ "E111",
88
+ "E114",
89
+ "E117",
90
+ "E501",
91
+ "Q000",
92
+ "Q001",
93
+ "Q002",
94
+ "Q003",
95
+ "W191",
96
+ ]
97
+ task-tags = ["TODO", "FIXME", "XXX", "HACK"]
98
+
99
+ [tool.ruff.lint.per-file-ignores]
100
+ "examples/**" = ["T201"]
101
+ "tests/**" = [
102
+ "ANN001",
103
+ "ANN201",
104
+ "PLR2004",
105
+ "S101",
106
+ "S105",
107
+ "S106",
108
+ ]
109
+
110
+ [tool.ruff.lint.pydocstyle]
111
+ convention = "google"
112
+
113
+ [tool.pyright]
114
+ pythonVersion = "3.14"
115
+ typeCheckingMode = "strict"
116
+ failOnWarnings = true
117
+ venvPath = "."
118
+ venv = ".venv"
119
+ extraPaths = ["src"]
120
+ exclude = [
121
+ "**/.venv",
122
+ ".venv",
123
+ ]
124
+
125
+ [dependency-groups]
126
+ dev = [
127
+ "build>=1.5.0",
128
+ "twine>=6.2.0",
129
+ ]
@@ -0,0 +1,34 @@
1
+ #!/usr/bin/env bash
2
+ # Run the same checks as CI / pre-commit (ruff, basedpyright, pytest).
3
+ # Usage: from repo root — make check or bash scripts/check.sh
4
+ set -euo pipefail
5
+
6
+ ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
7
+ cd "$ROOT"
8
+
9
+ run_checks() {
10
+ python -m ruff check .
11
+ python -m basedpyright
12
+ python -m pytest
13
+ }
14
+
15
+ if command -v uv >/dev/null 2>&1; then
16
+ # Resolves the project env (creates .venv / syncs deps if needed).
17
+ uv run --extra dev python -m ruff check .
18
+ uv run --extra dev python -m basedpyright
19
+ uv run --extra dev python -m pytest
20
+ exit 0
21
+ fi
22
+
23
+ if [[ -d .venv ]]; then
24
+ # shellcheck source=/dev/null
25
+ source "${ROOT}/.venv/bin/activate"
26
+ fi
27
+
28
+ if ! python -c "import bling_jwt_auth" 2>/dev/null; then
29
+ echo "error: bling_jwt_auth not importable — run: uv sync --extra dev" >&2
30
+ echo " (or: pip install -e '.[dev]')" >&2
31
+ exit 1
32
+ fi
33
+
34
+ run_checks
@@ -0,0 +1,31 @@
1
+ """Bling API v3 OAuth helpers (JWT-ready)."""
2
+
3
+ from bling_jwt_auth.config import BlingAuthSettings, TokenStoreKind
4
+ from bling_jwt_auth.exceptions import BlingAuthError, OAuthRequestError, TokenNotFoundError
5
+ from bling_jwt_auth.headers import bling_api_headers
6
+ from bling_jwt_auth.manager import TokenManager
7
+ from bling_jwt_auth.models.token import StoredToken, TokenResponse
8
+ from bling_jwt_auth.oauth.client import OAuthClient
9
+ from bling_jwt_auth.storage.base import TokenStore
10
+ from bling_jwt_auth.storage.factory import create_token_store
11
+ from bling_jwt_auth.storage.file import FileTokenStore
12
+ from bling_jwt_auth.storage.sqlite import SQLiteTokenStore
13
+
14
+ __all__ = [
15
+ "BlingAuthError",
16
+ "BlingAuthSettings",
17
+ "FileTokenStore",
18
+ "OAuthClient",
19
+ "OAuthRequestError",
20
+ "SQLiteTokenStore",
21
+ "StoredToken",
22
+ "TokenManager",
23
+ "TokenNotFoundError",
24
+ "TokenResponse",
25
+ "TokenStore",
26
+ "TokenStoreKind",
27
+ "bling_api_headers",
28
+ "create_token_store",
29
+ ]
30
+
31
+ __version__ = "0.1.0"