cqw 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.
cqw-0.1.0/.gitignore ADDED
@@ -0,0 +1,309 @@
1
+ ### Generated by gibo (https://github.com/simonwhitaker/gibo)
2
+ ### https://raw.github.com/github/gitignore/b4105e73e493bb7a20b5d7ea35efd5780ca44938/Global/VisualStudioCode.gitignore
3
+
4
+ .vscode/*
5
+ !.vscode/settings.json
6
+ !.vscode/tasks.json
7
+ !.vscode/launch.json
8
+ !.vscode/extensions.json
9
+ !.vscode/*.code-snippets
10
+ !*.code-workspace
11
+
12
+ # Built Visual Studio Code Extensions
13
+ *.vsix
14
+ ### Generated by gibo (https://github.com/simonwhitaker/gibo)
15
+ ### https://raw.github.com/github/gitignore/b4105e73e493bb7a20b5d7ea35efd5780ca44938/Global/Linux.gitignore
16
+
17
+ *~
18
+
19
+ # temporary files which can be created if a process still has a handle open of a deleted file
20
+ .fuse_hidden*
21
+
22
+ # Metadata left by Dolphin file manager, which comes with KDE Plasma
23
+ .directory
24
+
25
+ # Linux trash folder which might appear on any partition or disk
26
+ .Trash-*
27
+
28
+ # .nfs files are created when an open file is removed but is still being accessed
29
+ .nfs*
30
+
31
+ # Log files created by default by the nohup command
32
+ nohup.out
33
+ ### Generated by gibo (https://github.com/simonwhitaker/gibo)
34
+ ### https://raw.github.com/github/gitignore/b4105e73e493bb7a20b5d7ea35efd5780ca44938/Global/Windows.gitignore
35
+
36
+ # Windows thumbnail cache files
37
+ Thumbs.db
38
+ Thumbs.db:encryptable
39
+ ehthumbs.db
40
+ ehthumbs_vista.db
41
+
42
+ # Dump file
43
+ *.stackdump
44
+
45
+ # Folder config file
46
+ [Dd]esktop.ini
47
+
48
+ # Recycle Bin used on file shares
49
+ $RECYCLE.BIN/
50
+
51
+ # Windows Installer files
52
+ *.cab
53
+ *.msi
54
+ *.msix
55
+ *.msm
56
+ *.msp
57
+
58
+ # Windows shortcuts
59
+ *.lnk
60
+ ### Generated by gibo (https://github.com/simonwhitaker/gibo)
61
+ ### https://raw.github.com/github/gitignore/b4105e73e493bb7a20b5d7ea35efd5780ca44938/Global/macOS.gitignore
62
+
63
+ # General
64
+ .DS_Store
65
+ __MACOSX/
66
+ .AppleDouble
67
+ .LSOverride
68
+ Icon[
69
+ ]
70
+
71
+ # Thumbnails
72
+ ._*
73
+
74
+ # Files that might appear in the root of a volume
75
+ .DocumentRevisions-V100
76
+ .fseventsd
77
+ .Spotlight-V100
78
+ .TemporaryItems
79
+ .Trashes
80
+ .VolumeIcon.icns
81
+ .com.apple.timemachine.donotpresent
82
+
83
+ # Directories potentially created on remote AFP share
84
+ .AppleDB
85
+ .AppleDesktop
86
+ Network Trash Folder
87
+ Temporary Items
88
+ .apdisk
89
+ ### Generated by gibo (https://github.com/simonwhitaker/gibo)
90
+ ### https://raw.github.com/github/gitignore/b4105e73e493bb7a20b5d7ea35efd5780ca44938/Python.gitignore
91
+
92
+ # Byte-compiled / optimized / DLL files
93
+ __pycache__/
94
+ *.py[codz]
95
+ *$py.class
96
+
97
+ # C extensions
98
+ *.so
99
+
100
+ # Distribution / packaging
101
+ .Python
102
+ build/
103
+ develop-eggs/
104
+ dist/
105
+ downloads/
106
+ eggs/
107
+ .eggs/
108
+ lib/
109
+ lib64/
110
+ parts/
111
+ sdist/
112
+ var/
113
+ wheels/
114
+ share/python-wheels/
115
+ *.egg-info/
116
+ .installed.cfg
117
+ *.egg
118
+ MANIFEST
119
+
120
+ # PyInstaller
121
+ # Usually these files are written by a python script from a template
122
+ # before PyInstaller builds the exe, so as to inject date/other infos into it.
123
+ *.manifest
124
+ *.spec
125
+
126
+ # Installer logs
127
+ pip-log.txt
128
+ pip-delete-this-directory.txt
129
+
130
+ # Unit test / coverage reports
131
+ htmlcov/
132
+ .tox/
133
+ .nox/
134
+ .coverage
135
+ .coverage.*
136
+ .cache
137
+ nosetests.xml
138
+ coverage.xml
139
+ *.cover
140
+ *.py.cover
141
+ .hypothesis/
142
+ .pytest_cache/
143
+ cover/
144
+
145
+ # Translations
146
+ *.mo
147
+ *.pot
148
+
149
+ # Django stuff:
150
+ *.log
151
+ local_settings.py
152
+ db.sqlite3
153
+ db.sqlite3-journal
154
+
155
+ # Flask stuff:
156
+ instance/
157
+ .webassets-cache
158
+
159
+ # Scrapy stuff:
160
+ .scrapy
161
+
162
+ # Sphinx documentation
163
+ docs/_build/
164
+
165
+ # PyBuilder
166
+ .pybuilder/
167
+ target/
168
+
169
+ # Jupyter Notebook
170
+ .ipynb_checkpoints
171
+
172
+ # IPython
173
+ profile_default/
174
+ ipython_config.py
175
+
176
+ # pyenv
177
+ # For a library or package, you might want to ignore these files since the code is
178
+ # intended to run in multiple environments; otherwise, check them in:
179
+ # .python-version
180
+
181
+ # pipenv
182
+ # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
183
+ # However, in case of collaboration, if having platform-specific dependencies or dependencies
184
+ # having no cross-platform support, pipenv may install dependencies that don't work, or not
185
+ # install all needed dependencies.
186
+ # Pipfile.lock
187
+
188
+ # UV
189
+ # Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control.
190
+ # This is especially recommended for binary packages to ensure reproducibility, and is more
191
+ # commonly ignored for libraries.
192
+ # uv.lock
193
+
194
+ # poetry
195
+ # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
196
+ # This is especially recommended for binary packages to ensure reproducibility, and is more
197
+ # commonly ignored for libraries.
198
+ # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
199
+ # poetry.lock
200
+ # poetry.toml
201
+
202
+ # pdm
203
+ # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
204
+ # pdm recommends including project-wide configuration in pdm.toml, but excluding .pdm-python.
205
+ # https://pdm-project.org/en/latest/usage/project/#working-with-version-control
206
+ # pdm.lock
207
+ # pdm.toml
208
+ .pdm-python
209
+ .pdm-build/
210
+
211
+ # pixi
212
+ # Similar to Pipfile.lock, it is generally recommended to include pixi.lock in version control.
213
+ # pixi.lock
214
+ # Pixi creates a virtual environment in the .pixi directory, just like venv module creates one
215
+ # in the .venv directory. It is recommended not to include this directory in version control.
216
+ .pixi
217
+
218
+ # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
219
+ __pypackages__/
220
+
221
+ # Celery stuff
222
+ celerybeat-schedule
223
+ celerybeat.pid
224
+
225
+ # Redis
226
+ *.rdb
227
+ *.aof
228
+ *.pid
229
+
230
+ # RabbitMQ
231
+ mnesia/
232
+ rabbitmq/
233
+ rabbitmq-data/
234
+
235
+ # ActiveMQ
236
+ activemq-data/
237
+
238
+ # SageMath parsed files
239
+ *.sage.py
240
+
241
+ # Environments
242
+ .env
243
+ .envrc
244
+ .venv
245
+ env/
246
+ venv/
247
+ ENV/
248
+ env.bak/
249
+ venv.bak/
250
+
251
+ # Spyder project settings
252
+ .spyderproject
253
+ .spyproject
254
+
255
+ # Rope project settings
256
+ .ropeproject
257
+
258
+ # mkdocs documentation
259
+ /site
260
+
261
+ # mypy
262
+ .mypy_cache/
263
+ .dmypy.json
264
+ dmypy.json
265
+
266
+ # Pyre type checker
267
+ .pyre/
268
+
269
+ # pytype static type analyzer
270
+ .pytype/
271
+
272
+ # Cython debug symbols
273
+ cython_debug/
274
+
275
+ # PyCharm
276
+ # JetBrains specific template is maintained in a separate JetBrains.gitignore that can
277
+ # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
278
+ # and can be added to the global gitignore or merged into this file. For a more nuclear
279
+ # option (not recommended) you can uncomment the following to ignore the entire idea folder.
280
+ # .idea/
281
+
282
+ # Abstra
283
+ # Abstra is an AI-powered process automation framework.
284
+ # Ignore directories containing user credentials, local state, and settings.
285
+ # Learn more at https://abstra.io/docs
286
+ .abstra/
287
+
288
+ # Visual Studio Code
289
+ # Visual Studio Code specific template is maintained in a separate VisualStudioCode.gitignore
290
+ # that can be found at https://github.com/github/gitignore/blob/main/Global/VisualStudioCode.gitignore
291
+ # and can be added to the global gitignore or merged into this file. However, if you prefer,
292
+ # you could uncomment the following to ignore the entire vscode folder
293
+ # .vscode/
294
+
295
+ # Ruff stuff:
296
+ .ruff_cache/
297
+
298
+ # PyPI configuration file
299
+ .pypirc
300
+
301
+ # Marimo
302
+ marimo/_static/
303
+ marimo/_lsp/
304
+ __marimo__/
305
+
306
+ # Streamlit
307
+ .streamlit/secrets.toml
308
+
309
+ # Project specific
cqw-0.1.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 likeablob
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.
cqw-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,112 @@
1
+ Metadata-Version: 2.4
2
+ Name: cqw
3
+ Version: 0.1.0
4
+ Summary: Cloudflare Quick Tunnel wrapper with Basic Auth reverse proxy
5
+ Project-URL: Documentation, https://github.com/likeablob/cqw
6
+ Project-URL: Source, https://github.com/likeablob/cqw
7
+ License-File: LICENSE
8
+ Requires-Python: >=3.10
9
+ Requires-Dist: httpx>=0.28.1
10
+ Requires-Dist: platformdirs>=4.9.0
11
+ Requires-Dist: pydantic-settings>=2.14.1
12
+ Requires-Dist: qrcode>=8.2
13
+ Requires-Dist: rich>=15.0.0
14
+ Requires-Dist: starlette>=1.0.0
15
+ Requires-Dist: uvicorn>=0.46.0
16
+ Requires-Dist: websockets>=16.0
17
+ Description-Content-Type: text/markdown
18
+
19
+ # cqw
20
+
21
+ Cloudflare Quick Tunnel wrapper with Basic Auth reverse proxy.
22
+
23
+ ```
24
+ [Client] -> [Cloudflare Tunnel] -> [cqw Proxy (Basic Auth)] -> [Target Service]
25
+ ```
26
+
27
+ ## Installation
28
+
29
+ ```bash
30
+ uvx cqw
31
+ ```
32
+
33
+ Or with uv tool:
34
+
35
+ ```bash
36
+ uv tool install cqw
37
+ ```
38
+
39
+ ## Usage
40
+
41
+ ```bash
42
+ # Basic usage: creates tunnel with random credentials
43
+ cqw -f localhost:8080
44
+ ... # QR code with authenticated URL, tunnel URL, credentials
45
+
46
+ # Custom Basic Auth credentials
47
+ cqw -f localhost:8080 --user admin --pass secret
48
+
49
+ # Direct tunnel to target (bypass proxy and authentication)
50
+ # [Cloudflare Tunnel] -> [Target Service]
51
+ cqw -f localhost:8080 --no-proxy
52
+ ```
53
+
54
+ ## CLI Options
55
+
56
+ | Option | Description |
57
+ | -------------------------- | ---------------------------------------------------------------- |
58
+ | `-f, --forward` | Target address to forward (required) |
59
+ | `--user` | Basic auth username (default: env `CQW_USER` or random) |
60
+ | `--pass` | Basic auth password (default: env `CQW_PASS` or random) |
61
+ | `--cloudflared` | Path to cloudflared binary (default: auto-download to cache) |
62
+ | `--update-cloudflared` | Update cloudflared to latest version |
63
+ | `--no-qr` | Disable QR code display |
64
+ | `-v, --verbose` | Enable verbose logging |
65
+ | `--no-proxy` | Disable proxy and Basic Auth (tunnel only) |
66
+ | `--quiet` | Suppress cloudflared tunnel logs |
67
+ | `--cloudflared-extra-args` | Extra arguments passed to cloudflared (e.g., '--protocol http2') |
68
+
69
+ ## Environment Variables
70
+
71
+ - `CQW_USER`: Basic auth username (fallback: random)
72
+ - `CQW_PASS`: Basic auth password (fallback: random)
73
+
74
+ ## `cloudflared` Installation
75
+
76
+ `cloudflared` is automatically downloaded to the user cache directory on first run:
77
+
78
+ - Linux: `~/.cache/cqw/cloudflared/`
79
+ - macOS: `~/Library/Caches/cqw/cloudflared/`
80
+ - Windows: `%LOCALAPPDATA%\cqw\cloudflared\`
81
+
82
+ To update to the latest version:
83
+ ```bash
84
+ cqw -f localhost:8080 --update-cloudflared
85
+ ```
86
+
87
+ Manual download: https://github.com/cloudflare/cloudflared/releases
88
+
89
+ ## Development
90
+
91
+ ```bash
92
+ # Install tools
93
+ mise trust && mise install
94
+
95
+ # Install dependencies:
96
+ uv sync
97
+
98
+ # Install pre-commit hooks:
99
+ uv run pre-commit install
100
+
101
+ # Testing
102
+ uv run pytest tests/ -v
103
+
104
+ # Linting
105
+ uv run ruff check src/
106
+ uv run ruff format src/
107
+ uv run ty check src/ tests/
108
+ ```
109
+
110
+ ## LICENSE
111
+
112
+ MIT
cqw-0.1.0/README.md ADDED
@@ -0,0 +1,94 @@
1
+ # cqw
2
+
3
+ Cloudflare Quick Tunnel wrapper with Basic Auth reverse proxy.
4
+
5
+ ```
6
+ [Client] -> [Cloudflare Tunnel] -> [cqw Proxy (Basic Auth)] -> [Target Service]
7
+ ```
8
+
9
+ ## Installation
10
+
11
+ ```bash
12
+ uvx cqw
13
+ ```
14
+
15
+ Or with uv tool:
16
+
17
+ ```bash
18
+ uv tool install cqw
19
+ ```
20
+
21
+ ## Usage
22
+
23
+ ```bash
24
+ # Basic usage: creates tunnel with random credentials
25
+ cqw -f localhost:8080
26
+ ... # QR code with authenticated URL, tunnel URL, credentials
27
+
28
+ # Custom Basic Auth credentials
29
+ cqw -f localhost:8080 --user admin --pass secret
30
+
31
+ # Direct tunnel to target (bypass proxy and authentication)
32
+ # [Cloudflare Tunnel] -> [Target Service]
33
+ cqw -f localhost:8080 --no-proxy
34
+ ```
35
+
36
+ ## CLI Options
37
+
38
+ | Option | Description |
39
+ | -------------------------- | ---------------------------------------------------------------- |
40
+ | `-f, --forward` | Target address to forward (required) |
41
+ | `--user` | Basic auth username (default: env `CQW_USER` or random) |
42
+ | `--pass` | Basic auth password (default: env `CQW_PASS` or random) |
43
+ | `--cloudflared` | Path to cloudflared binary (default: auto-download to cache) |
44
+ | `--update-cloudflared` | Update cloudflared to latest version |
45
+ | `--no-qr` | Disable QR code display |
46
+ | `-v, --verbose` | Enable verbose logging |
47
+ | `--no-proxy` | Disable proxy and Basic Auth (tunnel only) |
48
+ | `--quiet` | Suppress cloudflared tunnel logs |
49
+ | `--cloudflared-extra-args` | Extra arguments passed to cloudflared (e.g., '--protocol http2') |
50
+
51
+ ## Environment Variables
52
+
53
+ - `CQW_USER`: Basic auth username (fallback: random)
54
+ - `CQW_PASS`: Basic auth password (fallback: random)
55
+
56
+ ## `cloudflared` Installation
57
+
58
+ `cloudflared` is automatically downloaded to the user cache directory on first run:
59
+
60
+ - Linux: `~/.cache/cqw/cloudflared/`
61
+ - macOS: `~/Library/Caches/cqw/cloudflared/`
62
+ - Windows: `%LOCALAPPDATA%\cqw\cloudflared\`
63
+
64
+ To update to the latest version:
65
+ ```bash
66
+ cqw -f localhost:8080 --update-cloudflared
67
+ ```
68
+
69
+ Manual download: https://github.com/cloudflare/cloudflared/releases
70
+
71
+ ## Development
72
+
73
+ ```bash
74
+ # Install tools
75
+ mise trust && mise install
76
+
77
+ # Install dependencies:
78
+ uv sync
79
+
80
+ # Install pre-commit hooks:
81
+ uv run pre-commit install
82
+
83
+ # Testing
84
+ uv run pytest tests/ -v
85
+
86
+ # Linting
87
+ uv run ruff check src/
88
+ uv run ruff format src/
89
+ uv run ty check src/ tests/
90
+ ```
91
+
92
+ ## LICENSE
93
+
94
+ MIT
@@ -0,0 +1,68 @@
1
+ [project]
2
+ name = "cqw"
3
+ version = "0.1.0"
4
+ description = "Cloudflare Quick Tunnel wrapper with Basic Auth reverse proxy"
5
+ readme = "README.md"
6
+ requires-python = ">=3.10"
7
+ dependencies = [
8
+ "httpx>=0.28.1",
9
+ "platformdirs>=4.9.0",
10
+ "pydantic-settings>=2.14.1",
11
+ "qrcode>=8.2",
12
+ "rich>=15.0.0",
13
+ "starlette>=1.0.0",
14
+ "uvicorn>=0.46.0",
15
+ "websockets>=16.0",
16
+ ]
17
+
18
+ [project.urls]
19
+ Documentation = "https://github.com/likeablob/cqw"
20
+ Source = "https://github.com/likeablob/cqw"
21
+
22
+ [project.scripts]
23
+ cqw = "cqw.main:main"
24
+
25
+ [tool.uv]
26
+ package = true
27
+
28
+ [build-system]
29
+ requires = ["hatchling"]
30
+ build-backend = "hatchling.build"
31
+
32
+ [tool.hatch.build.targets.sdist]
33
+ include = [
34
+ "/src",
35
+ "/README.md",
36
+ ]
37
+
38
+ [tool.hatch.build.targets.wheel]
39
+ packages = ["src/cqw"]
40
+
41
+ [dependency-groups]
42
+ dev = [
43
+ "pre-commit>=4.6.0",
44
+ "pytest>=9.0.0",
45
+ "pytest-asyncio>=1.3.0",
46
+ "ruff>=0.15.0",
47
+ "ty>=0.0.34",
48
+ ]
49
+
50
+ [tool.ruff]
51
+ line-length = 88
52
+ target-version = "py310"
53
+
54
+ [tool.ruff.lint]
55
+ select = ["E", "F", "W", "I", "N", "B", "C4", "UP"]
56
+ ignore = ["E501", "B008"]
57
+
58
+ [tool.ruff.lint.isort]
59
+ combine-as-imports = true
60
+
61
+ [tool.pytest.ini_options]
62
+ testpaths = ["tests"]
63
+ python_files = ["test_*.py"]
64
+ asyncio_mode = "auto"
65
+
66
+ [tool.ty.rules]
67
+ invalid-parameter-default = "ignore"
68
+ missing-argument = "ignore"
@@ -0,0 +1 @@
1
+ __version__ = "0.1.0"
@@ -0,0 +1,98 @@
1
+ import random
2
+ import shlex
3
+ import string
4
+
5
+ from pydantic import AliasChoices, Field
6
+ from pydantic_settings import (
7
+ BaseSettings,
8
+ CliSettingsSource,
9
+ PydanticBaseSettingsSource,
10
+ SettingsConfigDict,
11
+ )
12
+
13
+
14
+ def generate_random_credential(length: int = 8) -> str:
15
+ chars = string.ascii_letters + string.digits
16
+ return "".join(random.choice(chars) for _ in range(length))
17
+
18
+
19
+ class Settings(BaseSettings):
20
+ forward: str = Field(description="Target address to forward (e.g., localhost:8080)")
21
+ user: str = Field(
22
+ default_factory=generate_random_credential, description="Basic auth username"
23
+ )
24
+ password: str = Field(
25
+ default_factory=generate_random_credential,
26
+ validation_alias=AliasChoices("password", "pass"),
27
+ description="Basic auth password",
28
+ )
29
+ cloudflared: str = Field(
30
+ default="", description="Path to cloudflared binary (default: auto-download)"
31
+ )
32
+ update_cloudflared: bool = Field(
33
+ default=False, description="Update cloudflared to latest version"
34
+ )
35
+ qr: bool = Field(default=True, description="Display QR code with authenticated URL")
36
+ verbose: bool = Field(default=False, description="Enable verbose logging")
37
+ no_proxy: bool = Field(
38
+ default=False, description="Disable proxy and Basic Auth (tunnel only)"
39
+ )
40
+ quiet: bool = Field(default=False, description="Suppress cloudflared tunnel logs")
41
+ cloudflared_extra_args: str = Field(
42
+ default="",
43
+ description="Extra arguments passed to cloudflared (e.g., '--protocol http2')",
44
+ )
45
+
46
+ model_config = SettingsConfigDict(
47
+ env_prefix="CQW_",
48
+ env_prefix_target="all",
49
+ case_sensitive=False,
50
+ env_file=".env",
51
+ extra="ignore",
52
+ )
53
+
54
+ @property
55
+ def forward_url(self) -> str:
56
+ if self.forward.startswith(("http://", "https://")):
57
+ return self.forward
58
+ return f"http://{self.forward}"
59
+
60
+ @property
61
+ def cloudflared_args_list(self) -> list[str]:
62
+ if self.cloudflared_extra_args:
63
+ return shlex.split(self.cloudflared_extra_args)
64
+ return []
65
+
66
+
67
+ class CLISettings(Settings):
68
+ model_config = SettingsConfigDict(
69
+ cli_parse_args=True,
70
+ cli_prog_name="cqw",
71
+ cli_exit_on_error=True,
72
+ cli_enforce_required=True,
73
+ cli_shortcuts={
74
+ "forward": "f",
75
+ "verbose": "v",
76
+ },
77
+ cli_implicit_flags=True,
78
+ )
79
+
80
+ @classmethod
81
+ def settings_customise_sources(
82
+ cls,
83
+ settings_cls: type[BaseSettings],
84
+ init_settings: PydanticBaseSettingsSource,
85
+ env_settings: PydanticBaseSettingsSource,
86
+ dotenv_settings: PydanticBaseSettingsSource,
87
+ file_secret_settings: PydanticBaseSettingsSource,
88
+ ) -> tuple[PydanticBaseSettingsSource, ...]:
89
+ return (
90
+ init_settings,
91
+ CliSettingsSource(
92
+ settings_cls,
93
+ cli_parse_args=True,
94
+ cli_kebab_case=True,
95
+ ),
96
+ env_settings,
97
+ dotenv_settings,
98
+ )