reflex-hosting-cli 0.1.72a1__tar.gz → 0.2.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.
- {reflex_hosting_cli-0.1.72a1 → reflex_hosting_cli-0.2.0}/.gitignore +8 -1
- {reflex_hosting_cli-0.1.72a1 → reflex_hosting_cli-0.2.0}/CHANGELOG.md +31 -1
- {reflex_hosting_cli-0.1.72a1 → reflex_hosting_cli-0.2.0}/PKG-INFO +9 -2
- reflex_hosting_cli-0.2.0/pyproject.toml +55 -0
- {reflex_hosting_cli-0.1.72a1 → reflex_hosting_cli-0.2.0}/src/reflex_cli/constants/hosting.py +3 -0
- {reflex_hosting_cli-0.1.72a1 → reflex_hosting_cli-0.2.0}/src/reflex_cli/utils/console.py +83 -40
- {reflex_hosting_cli-0.1.72a1 → reflex_hosting_cli-0.2.0}/src/reflex_cli/utils/dependency.py +2 -2
- reflex_hosting_cli-0.2.0/src/reflex_cli/utils/hosting.py +1873 -0
- {reflex_hosting_cli-0.1.72a1 → reflex_hosting_cli-0.2.0}/src/reflex_cli/v2/apps.py +220 -302
- {reflex_hosting_cli-0.1.72a1 → reflex_hosting_cli-0.2.0}/src/reflex_cli/v2/auth.py +1 -4
- {reflex_hosting_cli-0.1.72a1 → reflex_hosting_cli-0.2.0}/src/reflex_cli/v2/cli.py +274 -151
- {reflex_hosting_cli-0.1.72a1 → reflex_hosting_cli-0.2.0}/src/reflex_cli/v2/gcp.py +28 -49
- reflex_hosting_cli-0.2.0/src/reflex_cli/v2/project.py +434 -0
- {reflex_hosting_cli-0.1.72a1 → reflex_hosting_cli-0.2.0}/src/reflex_cli/v2/providers.py +62 -78
- {reflex_hosting_cli-0.1.72a1 → reflex_hosting_cli-0.2.0}/src/reflex_cli/v2/scan.py +27 -32
- {reflex_hosting_cli-0.1.72a1 → reflex_hosting_cli-0.2.0}/src/reflex_cli/v2/secrets.py +33 -33
- {reflex_hosting_cli-0.1.72a1 → reflex_hosting_cli-0.2.0}/src/reflex_cli/v2/vmtypes_regions.py +18 -7
- reflex_hosting_cli-0.1.72a1/pyproject.toml +0 -36
- reflex_hosting_cli-0.1.72a1/src/reflex_cli/utils/hosting.py +0 -3487
- reflex_hosting_cli-0.1.72a1/src/reflex_cli/v2/project.py +0 -492
- {reflex_hosting_cli-0.1.72a1 → reflex_hosting_cli-0.2.0}/README.md +0 -0
- {reflex_hosting_cli-0.1.72a1 → reflex_hosting_cli-0.2.0}/news/.gitkeep +0 -0
- {reflex_hosting_cli-0.1.72a1 → reflex_hosting_cli-0.2.0}/src/reflex_cli/__init__.py +0 -0
- {reflex_hosting_cli-0.1.72a1 → reflex_hosting_cli-0.2.0}/src/reflex_cli/cli.py +0 -0
- {reflex_hosting_cli-0.1.72a1 → reflex_hosting_cli-0.2.0}/src/reflex_cli/constants/__init__.py +0 -0
- {reflex_hosting_cli-0.1.72a1 → reflex_hosting_cli-0.2.0}/src/reflex_cli/constants/base.py +0 -0
- {reflex_hosting_cli-0.1.72a1 → reflex_hosting_cli-0.2.0}/src/reflex_cli/constants/compiler.py +0 -0
- {reflex_hosting_cli-0.1.72a1 → reflex_hosting_cli-0.2.0}/src/reflex_cli/constants/log_level.py +0 -0
- {reflex_hosting_cli-0.1.72a1 → reflex_hosting_cli-0.2.0}/src/reflex_cli/core/__init__.py +0 -0
- {reflex_hosting_cli-0.1.72a1 → reflex_hosting_cli-0.2.0}/src/reflex_cli/core/config.py +0 -0
- {reflex_hosting_cli-0.1.72a1 → reflex_hosting_cli-0.2.0}/src/reflex_cli/deployments.py +0 -0
- {reflex_hosting_cli-0.1.72a1 → reflex_hosting_cli-0.2.0}/src/reflex_cli/utils/__init__.py +0 -0
- {reflex_hosting_cli-0.1.72a1 → reflex_hosting_cli-0.2.0}/src/reflex_cli/utils/cli_options.py +0 -0
- {reflex_hosting_cli-0.1.72a1 → reflex_hosting_cli-0.2.0}/src/reflex_cli/utils/exceptions.py +0 -0
- {reflex_hosting_cli-0.1.72a1 → reflex_hosting_cli-0.2.0}/src/reflex_cli/utils/log.py +0 -0
- {reflex_hosting_cli-0.1.72a1 → reflex_hosting_cli-0.2.0}/src/reflex_cli/utils/output.py +0 -0
- {reflex_hosting_cli-0.1.72a1 → reflex_hosting_cli-0.2.0}/src/reflex_cli/v2/__init__.py +0 -0
- {reflex_hosting_cli-0.1.72a1 → reflex_hosting_cli-0.2.0}/src/reflex_cli/v2/deploy.py +0 -0
- {reflex_hosting_cli-0.1.72a1 → reflex_hosting_cli-0.2.0}/src/reflex_cli/v2/deployments.py +0 -0
- {reflex_hosting_cli-0.1.72a1 → reflex_hosting_cli-0.2.0}/src/reflex_cli/v2/utils.py +0 -0
|
@@ -7,7 +7,13 @@
|
|
|
7
7
|
.mypy_cache/
|
|
8
8
|
assets/external/*
|
|
9
9
|
dist/*
|
|
10
|
-
examples/
|
|
10
|
+
# Only the tracked examples; private apps under examples/ stay ignored. The
|
|
11
|
+
# pattern has a separator in the middle, so it is anchored to this directory
|
|
12
|
+
# and leaves the examples that live inside packages and tests alone.
|
|
13
|
+
examples/*
|
|
14
|
+
!examples/README.md
|
|
15
|
+
!examples/ruff.toml
|
|
16
|
+
!examples/playground/
|
|
11
17
|
.web
|
|
12
18
|
.states
|
|
13
19
|
.idea
|
|
@@ -21,6 +27,7 @@ requirements.txt
|
|
|
21
27
|
.pyi_generator_diff
|
|
22
28
|
reflex.db
|
|
23
29
|
.codspeed
|
|
30
|
+
.reflex-bench/
|
|
24
31
|
.env
|
|
25
32
|
.env.*
|
|
26
33
|
node_modules
|
|
@@ -1,4 +1,34 @@
|
|
|
1
|
-
## v0.
|
|
1
|
+
## v0.2.0 (2026-10-08)
|
|
2
|
+
|
|
3
|
+
### Breaking Changes
|
|
4
|
+
|
|
5
|
+
- Some `reflex cloud` commands changed what they report: ([#7207](https://github.com/reflex-dev/reflex/issues/7207))
|
|
6
|
+
- A refused request exits non-zero instead of printing a `"... failed: ..."` line and exiting 0, and `--json` writes no document. This includes `vmtypes` and `regions`, which answered a failed request with an empty listing, and `apps stop`, `apps start` and `apps delete`, which now report their own outcome rather than echoing the server's message.
|
|
7
|
+
- `apps history --json` replaces `hostname` with the deployment's `url`, reports `vm type` as the machine's name rather than an object, and reports `timestamp` as an ISO 8601 string with an offset. `apps inspect --json` drops `hostname` from `latest_deployment`.
|
|
8
|
+
- `create-token --json` replaces `expires_in_days` with `expires_at`, an ISO 8601 string or `null`, carrying the expiry the server applied.
|
|
9
|
+
- `apps logs` drops its unused `--cursor` option, and its `--json` document returns every line in the window rather than one page.
|
|
10
|
+
- `apps status --watch --json` reports `"success": null` when the watch stopped before the deployment finished.
|
|
11
|
+
- `project role-permissions` lists permission names rather than objects.
|
|
12
|
+
- `reflex deploy` requires a control plane that signs upload URLs; the multipart upload fallback for older ones, and its "payload is too large (over 100MB)" hint, are gone.
|
|
13
|
+
- Require Python 3.11 or newer; Python 3.10 is no longer supported. ([#7449](https://github.com/reflex-dev/reflex/issues/7449))
|
|
14
|
+
|
|
15
|
+
### Bug Fixes
|
|
16
|
+
|
|
17
|
+
- `reflex cloud` reports a refusal as the sentence the API wrote rather than a message of its own, and an expired token now says to run `reflex login` wherever it turns up — not only where a command started by authenticating. ([#7207](https://github.com/reflex-dev/reflex/issues/7207))
|
|
18
|
+
- `reflex cloud apps delete` now exits non-zero when the app ID is not found. ([#7295](https://github.com/reflex-dev/reflex/issues/7295))
|
|
19
|
+
- With `--no-interactive`, a rejected access token now fails right away with the same message `reflex cloud whoami` gives, instead of starting the browser login. ([#7298](https://github.com/reflex-dev/reflex/issues/7298))
|
|
20
|
+
- Preserve a different stored access token when authentication rejects an outdated or explicitly supplied token. ([#7321](https://github.com/reflex-dev/reflex/issues/7321))
|
|
21
|
+
- `reflex deploy` now consistently shows the "Built with Reflex" badge on apps deployed on the free tier, including apps built with earlier reflex releases. Paid plans can still hide it with `show_built_with_reflex=False`. ([#7333](https://github.com/reflex-dev/reflex/issues/7333))
|
|
22
|
+
- `reflex cloud apps list`, `apps history` and `apps inspect` keep app names and app and deployment IDs whole on one line, so you can copy them from a normal-width terminal. `apps list` and `apps history` show fewer columns; `--json` still returns every field. `apps inspect` shows one field per row. Tables no longer draw cell borders. ([#7351](https://github.com/reflex-dev/reflex/issues/7351))
|
|
23
|
+
- `reflex cloud secrets update` now prints a success line naming the keys it set and whether the app is rebooting, like `secrets delete` already did. Only key names are printed; values are never logged. ([#7352](https://github.com/reflex-dev/reflex/issues/7352))
|
|
24
|
+
- Fail `reflex deploy` before building when an explicitly requested project does not exist or does not own the selected app. Accept equivalent UUID spellings, including uppercase and unhyphenated project IDs. ([#7355](https://github.com/reflex-dev/reflex/issues/7355))
|
|
25
|
+
|
|
26
|
+
### Miscellaneous
|
|
27
|
+
|
|
28
|
+
- `reflex-hosting-cli` now talks to Reflex Build through `reflex-build-sdk`, so every command shares the SDK's retries, timeouts and typed errors. While the SDK is pre-1.0, the CLI pins it to a single patch line, so upgrade `reflex-hosting-cli` to move to a newer SDK rather than upgrading the SDK on its own. ([#7207](https://github.com/reflex-dev/reflex/issues/7207))
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
## v0.1.72 (2026-09-11)
|
|
2
32
|
|
|
3
33
|
### Breaking Changes
|
|
4
34
|
|
|
@@ -1,15 +1,22 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: reflex-hosting-cli
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.2.0
|
|
4
4
|
Summary: Reflex Hosting CLI
|
|
5
5
|
Author-email: Nikhil Rao <nikhil@reflex.dev>, Alek Petuskey <alek@reflex.dev>
|
|
6
6
|
Maintainer-email: Simon Young <simon@reflex.dev>, Khaleel Al-Adhami <khaleel@reflex.dev>
|
|
7
7
|
License: Apache-2.0
|
|
8
|
-
|
|
8
|
+
Classifier: Programming Language :: Python :: 3
|
|
9
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
10
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.15
|
|
14
|
+
Requires-Python: >=3.11
|
|
9
15
|
Requires-Dist: click>=8.2
|
|
10
16
|
Requires-Dist: httpx<1.0,>=0.25.1
|
|
11
17
|
Requires-Dist: packaging>=24.2
|
|
12
18
|
Requires-Dist: platformdirs<5.0,>=3.10.0
|
|
19
|
+
Requires-Dist: reflex-build-sdk[httpx]!=0.1.1,<0.1.1.post,>=0.1.0
|
|
13
20
|
Requires-Dist: rich<16,>=13
|
|
14
21
|
Description-Content-Type: text/markdown
|
|
15
22
|
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "reflex-hosting-cli"
|
|
3
|
+
dynamic = ["version"]
|
|
4
|
+
description = "Reflex Hosting CLI"
|
|
5
|
+
license.text = "Apache-2.0"
|
|
6
|
+
readme = "README.md"
|
|
7
|
+
authors = [
|
|
8
|
+
{ name = "Nikhil Rao", email = "nikhil@reflex.dev" },
|
|
9
|
+
{ name = "Alek Petuskey", email = "alek@reflex.dev" },
|
|
10
|
+
]
|
|
11
|
+
maintainers = [
|
|
12
|
+
{ name = "Simon Young", email = "simon@reflex.dev" },
|
|
13
|
+
{ name = "Khaleel Al-Adhami", email = "khaleel@reflex.dev" },
|
|
14
|
+
]
|
|
15
|
+
requires-python = ">=3.11"
|
|
16
|
+
classifiers = [
|
|
17
|
+
"Programming Language :: Python :: 3",
|
|
18
|
+
"Programming Language :: Python :: 3.11",
|
|
19
|
+
"Programming Language :: Python :: 3.12",
|
|
20
|
+
"Programming Language :: Python :: 3.13",
|
|
21
|
+
"Programming Language :: Python :: 3.14",
|
|
22
|
+
"Programming Language :: Python :: 3.15",
|
|
23
|
+
]
|
|
24
|
+
dependencies = [
|
|
25
|
+
"click >=8.2",
|
|
26
|
+
# Imported directly by `check_version`, so it is declared here rather than
|
|
27
|
+
# taken on loan from reflex-build-sdk's own pin.
|
|
28
|
+
"httpx >=0.25.1,<1.0",
|
|
29
|
+
"packaging >=24.2",
|
|
30
|
+
"platformdirs >=3.10.0,<5.0",
|
|
31
|
+
# The SDK ships no HTTP library of its own; [httpx] points it at the one
|
|
32
|
+
# `check_version` already pulls in, so the extra costs nothing to install.
|
|
33
|
+
# The SDK is pre-1.0, so every release may break its API: cap at the patch
|
|
34
|
+
# and raise all three bounds when adopting a new one. The floor admits the
|
|
35
|
+
# workspace's dev build until the 0.1.0 alpha publishes and materialization
|
|
36
|
+
# lifts it; the cap admits 0.1.0 and the ``0.1.1.devN`` builds that follow
|
|
37
|
+
# its tag, but not 0.1.1 itself.
|
|
38
|
+
"reflex-build-sdk[httpx] >=0.1.0,<0.1.1.post,!=0.1.1",
|
|
39
|
+
"rich >=13,<16",
|
|
40
|
+
]
|
|
41
|
+
|
|
42
|
+
[tool.hatch.version]
|
|
43
|
+
source = "uv-dynamic-versioning"
|
|
44
|
+
|
|
45
|
+
[tool.uv-dynamic-versioning]
|
|
46
|
+
pattern-prefix = "reflex-hosting-cli-"
|
|
47
|
+
fallback-version = "0.0.0dev0"
|
|
48
|
+
bump = true
|
|
49
|
+
|
|
50
|
+
[tool.hatch.build.targets.wheel]
|
|
51
|
+
packages = ["src/reflex_cli"]
|
|
52
|
+
|
|
53
|
+
[build-system]
|
|
54
|
+
requires = ["hatchling", "uv-dynamic-versioning"]
|
|
55
|
+
build-backend = "hatchling.build"
|
{reflex_hosting_cli-0.1.72a1 → reflex_hosting_cli-0.2.0}/src/reflex_cli/constants/hosting.py
RENAMED
|
@@ -41,6 +41,9 @@ class Hosting(SimpleNamespace):
|
|
|
41
41
|
# How long to wait between retry attempts
|
|
42
42
|
AUTH_RETRY_SLEEP_DURATION = 5
|
|
43
43
|
|
|
44
|
+
# Tiers (lowercased) whose deploys may hide the "Built with Reflex" badge
|
|
45
|
+
PAID_TIERS = frozenset(("pro", "team", "enterprise"))
|
|
46
|
+
|
|
44
47
|
# Aliases for compatibility with previous versions of Reflex
|
|
45
48
|
CP_BACKEND_URL = HOSTING_SERVICE
|
|
46
49
|
CP_WEB_URL = HOSTING_SERVICE_UI
|
|
@@ -7,37 +7,104 @@ prompts, tables, spinners and plain prints.
|
|
|
7
7
|
|
|
8
8
|
from __future__ import annotations
|
|
9
9
|
|
|
10
|
-
from collections.abc import Sequence
|
|
10
|
+
from collections.abc import Collection, Sequence
|
|
11
11
|
from typing import overload
|
|
12
12
|
|
|
13
|
+
from rich import box
|
|
14
|
+
from rich.cells import cell_len
|
|
15
|
+
from rich.console import Console, OverflowMethod
|
|
16
|
+
from rich.table import Table
|
|
17
|
+
|
|
13
18
|
from reflex_cli.constants.base import LogLevel
|
|
14
19
|
from reflex_cli.utils.log import HAS_REFLEX_BASE, is_json_mode, is_stdout_reserved
|
|
15
20
|
from reflex_cli.utils.log import set_log_level as _set_log_level
|
|
16
21
|
|
|
22
|
+
# The narrowest a folding table column gets before rows print as blocks.
|
|
23
|
+
_MIN_FOLD_WIDTH = 8
|
|
24
|
+
|
|
25
|
+
_console = Console(highlight=False)
|
|
26
|
+
_console_stderr = Console(stderr=True, highlight=False)
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def _human_console() -> Console:
|
|
30
|
+
"""Resolve the console human-readable output belongs on.
|
|
31
|
+
|
|
32
|
+
Returns:
|
|
33
|
+
The stderr console while stdout is carrying a machine-readable
|
|
34
|
+
document, and the stdout console otherwise.
|
|
35
|
+
"""
|
|
36
|
+
return _console_stderr if is_stdout_reserved() else _console
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def print_table(
|
|
40
|
+
tabular_data: list[list[str]],
|
|
41
|
+
headers: Sequence[str] = (),
|
|
42
|
+
overflow: OverflowMethod = "ellipsis",
|
|
43
|
+
no_wrap: Collection[str] = (),
|
|
44
|
+
) -> None:
|
|
45
|
+
"""Print a table to the console.
|
|
46
|
+
|
|
47
|
+
Args:
|
|
48
|
+
tabular_data: The data to print in tabular format.
|
|
49
|
+
headers: The headers for the table.
|
|
50
|
+
overflow: What to do with a cell too wide for its column. The default
|
|
51
|
+
cuts it short; pass "fold" for values a user has to read in full,
|
|
52
|
+
such as an email or an identifier.
|
|
53
|
+
no_wrap: Headers of the columns whose values stay on one line, so a
|
|
54
|
+
user can copy them. The other columns give up the width. When the
|
|
55
|
+
terminal is too narrow for that, each row prints as a block of
|
|
56
|
+
header and value lines instead, so no value is cut or squeezed.
|
|
57
|
+
"""
|
|
58
|
+
if is_json_mode():
|
|
59
|
+
# Only reflex-base has a JSON mode. Pass just the arguments every
|
|
60
|
+
# reflex-base release accepts.
|
|
61
|
+
from reflex_base.utils.console import print_table as base_print_table
|
|
62
|
+
|
|
63
|
+
base_print_table(tabular_data, headers=headers)
|
|
64
|
+
return
|
|
65
|
+
console = _human_console()
|
|
66
|
+
# A no_wrap column needs its widest value; a folding column that much up to
|
|
67
|
+
# _MIN_FOLD_WIDTH, so it stays readable.
|
|
68
|
+
min_widths = []
|
|
69
|
+
for index, column in enumerate(headers):
|
|
70
|
+
# Rows may be shorter than headers; the table leaves their tail blank.
|
|
71
|
+
values = (cell_len(row[index]) for row in tabular_data if index < len(row))
|
|
72
|
+
widest = max(cell_len(column), max(values, default=0))
|
|
73
|
+
min_widths.append(widest if column in no_wrap else min(widest, _MIN_FOLD_WIDTH))
|
|
74
|
+
# Each column also takes 3 cells of padding and gap, plus 1 for the edge.
|
|
75
|
+
if tabular_data and sum(min_widths) + 3 * len(headers) + 1 > console.width:
|
|
76
|
+
label_width = max(map(cell_len, headers), default=0)
|
|
77
|
+
for row in tabular_data:
|
|
78
|
+
for column, value in zip(headers, row, strict=False):
|
|
79
|
+
console.print(
|
|
80
|
+
f"{column.ljust(label_width)} {value}",
|
|
81
|
+
markup=False,
|
|
82
|
+
soft_wrap=True,
|
|
83
|
+
)
|
|
84
|
+
console.print()
|
|
85
|
+
return
|
|
86
|
+
table = Table(box=box.SIMPLE_HEAD)
|
|
87
|
+
|
|
88
|
+
for column, min_width in zip(headers, min_widths, strict=True):
|
|
89
|
+
table.add_column(
|
|
90
|
+
column, overflow=overflow, no_wrap=column in no_wrap, min_width=min_width
|
|
91
|
+
)
|
|
92
|
+
|
|
93
|
+
for row in tabular_data:
|
|
94
|
+
table.add_row(*row)
|
|
95
|
+
|
|
96
|
+
console.print(table)
|
|
97
|
+
|
|
98
|
+
|
|
17
99
|
if HAS_REFLEX_BASE:
|
|
18
100
|
from reflex_base.utils.console import ask as ask
|
|
19
101
|
from reflex_base.utils.console import print as print
|
|
20
|
-
from reflex_base.utils.console import print_table as print_table
|
|
21
102
|
from reflex_base.utils.console import progress as progress
|
|
22
103
|
from reflex_base.utils.console import rule as rule
|
|
23
104
|
from reflex_base.utils.console import status as status
|
|
24
105
|
else:
|
|
25
|
-
from rich.console import Console, OverflowMethod
|
|
26
106
|
from rich.progress import MofNCompleteColumn, Progress, TimeElapsedColumn
|
|
27
107
|
from rich.prompt import Prompt
|
|
28
|
-
from rich.table import Table
|
|
29
|
-
|
|
30
|
-
_console = Console(highlight=False)
|
|
31
|
-
_console_stderr = Console(stderr=True, highlight=False)
|
|
32
|
-
|
|
33
|
-
def _human_console() -> Console:
|
|
34
|
-
"""Resolve the console human-readable output belongs on.
|
|
35
|
-
|
|
36
|
-
Returns:
|
|
37
|
-
The stderr console while stdout is carrying a machine-readable
|
|
38
|
-
document, and the stdout console otherwise.
|
|
39
|
-
"""
|
|
40
|
-
return _console_stderr if is_stdout_reserved() else _console
|
|
41
108
|
|
|
42
109
|
def print(msg: str, **kwargs):
|
|
43
110
|
"""Print a message.
|
|
@@ -48,30 +115,6 @@ else:
|
|
|
48
115
|
"""
|
|
49
116
|
_human_console().print(msg, **kwargs)
|
|
50
117
|
|
|
51
|
-
def print_table(
|
|
52
|
-
tabular_data: list[list[str]],
|
|
53
|
-
headers: Sequence[str] = (),
|
|
54
|
-
overflow: OverflowMethod = "ellipsis",
|
|
55
|
-
) -> None:
|
|
56
|
-
"""Print a table to the console.
|
|
57
|
-
|
|
58
|
-
Args:
|
|
59
|
-
tabular_data: The data to print in tabular format.
|
|
60
|
-
headers: The headers for the table.
|
|
61
|
-
overflow: What to do with a cell too wide for its column. The
|
|
62
|
-
default cuts it short; pass "fold" for values a user has to
|
|
63
|
-
read in full, such as an email or an identifier.
|
|
64
|
-
"""
|
|
65
|
-
table = Table()
|
|
66
|
-
|
|
67
|
-
for column in headers:
|
|
68
|
-
table.add_column(column, overflow=overflow)
|
|
69
|
-
|
|
70
|
-
for row in tabular_data:
|
|
71
|
-
table.add_row(*row)
|
|
72
|
-
|
|
73
|
-
_human_console().print(table)
|
|
74
|
-
|
|
75
118
|
def rule(title: str, **kwargs):
|
|
76
119
|
"""Print a horizontal rule with a title.
|
|
77
120
|
|
|
@@ -34,12 +34,12 @@ def detect_encoding(filename: Path) -> str | None:
|
|
|
34
34
|
raise FileNotFoundError
|
|
35
35
|
|
|
36
36
|
for encoding in [
|
|
37
|
-
|
|
37
|
+
io.text_encoding(None),
|
|
38
38
|
"utf-8",
|
|
39
39
|
]:
|
|
40
40
|
try:
|
|
41
41
|
filename.read_text(encoding)
|
|
42
|
-
except UnicodeDecodeError:
|
|
42
|
+
except UnicodeDecodeError:
|
|
43
43
|
continue
|
|
44
44
|
except Exception:
|
|
45
45
|
return None
|