reflex 0.4.7a3__py3-none-any.whl → 0.4.8a1__py3-none-any.whl
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.
Potentially problematic release.
This version of reflex might be problematic. Click here for more details.
- reflex/.templates/web/utils/state.js +7 -1
- reflex/app.py +15 -1
- reflex/compiler/utils.py +1 -1
- reflex/components/base/body.pyi +0 -3
- reflex/components/base/document.pyi +0 -15
- reflex/components/base/fragment.pyi +0 -3
- reflex/components/base/head.pyi +0 -3
- reflex/components/base/link.pyi +0 -6
- reflex/components/base/meta.pyi +0 -12
- reflex/components/chakra/base.pyi +0 -6
- reflex/components/chakra/datadisplay/badge.pyi +0 -3
- reflex/components/chakra/datadisplay/code.pyi +0 -3
- reflex/components/chakra/datadisplay/divider.pyi +0 -3
- reflex/components/chakra/datadisplay/keyboard_key.pyi +0 -3
- reflex/components/chakra/datadisplay/list.pyi +0 -3
- reflex/components/chakra/datadisplay/stat.pyi +0 -15
- reflex/components/chakra/datadisplay/table.pyi +0 -12
- reflex/components/chakra/datadisplay/tag.pyi +0 -12
- reflex/components/chakra/disclosure/accordion.pyi +0 -12
- reflex/components/chakra/disclosure/tabs.pyi +0 -12
- reflex/components/chakra/disclosure/transition.pyi +0 -18
- reflex/components/chakra/disclosure/visuallyhidden.pyi +0 -3
- reflex/components/chakra/feedback/alert.pyi +0 -9
- reflex/components/chakra/feedback/circularprogress.pyi +0 -3
- reflex/components/chakra/feedback/progress.pyi +0 -3
- reflex/components/chakra/feedback/skeleton.pyi +0 -9
- reflex/components/chakra/feedback/spinner.pyi +0 -3
- reflex/components/chakra/forms/button.pyi +0 -6
- reflex/components/chakra/forms/checkbox.pyi +0 -6
- reflex/components/chakra/forms/colormodeswitch.pyi +0 -3
- reflex/components/chakra/forms/editable.pyi +0 -12
- reflex/components/chakra/forms/form.pyi +0 -9
- reflex/components/chakra/forms/iconbutton.pyi +0 -3
- reflex/components/chakra/forms/input.pyi +0 -15
- reflex/components/chakra/forms/numberinput.pyi +0 -12
- reflex/components/chakra/forms/pininput.py +1 -1
- reflex/components/chakra/forms/pininput.pyi +1 -4
- reflex/components/chakra/forms/radio.py +1 -1
- reflex/components/chakra/forms/radio.pyi +1 -1
- reflex/components/chakra/forms/rangeslider.py +1 -1
- reflex/components/chakra/forms/rangeslider.pyi +1 -10
- reflex/components/chakra/forms/slider.pyi +0 -12
- reflex/components/chakra/forms/switch.pyi +0 -3
- reflex/components/chakra/layout/aspect_ratio.pyi +0 -3
- reflex/components/chakra/layout/box.pyi +0 -3
- reflex/components/chakra/layout/card.pyi +0 -9
- reflex/components/chakra/layout/center.pyi +0 -9
- reflex/components/chakra/layout/container.pyi +0 -3
- reflex/components/chakra/layout/flex.pyi +0 -3
- reflex/components/chakra/layout/grid.pyi +0 -9
- reflex/components/chakra/layout/spacer.pyi +0 -3
- reflex/components/chakra/layout/stack.pyi +0 -9
- reflex/components/chakra/layout/wrap.pyi +0 -3
- reflex/components/chakra/media/avatar.pyi +0 -9
- reflex/components/chakra/media/icon.pyi +0 -3
- reflex/components/chakra/navigation/breadcrumb.pyi +0 -3
- reflex/components/chakra/navigation/linkoverlay.pyi +0 -6
- reflex/components/chakra/navigation/stepper.pyi +0 -24
- reflex/components/chakra/overlay/alertdialog.pyi +0 -18
- reflex/components/chakra/overlay/drawer.pyi +0 -18
- reflex/components/chakra/overlay/menu.pyi +0 -18
- reflex/components/chakra/overlay/modal.pyi +0 -18
- reflex/components/chakra/overlay/popover.pyi +0 -24
- reflex/components/chakra/overlay/tooltip.pyi +0 -3
- reflex/components/chakra/typography/heading.pyi +0 -3
- reflex/components/chakra/typography/highlight.pyi +0 -3
- reflex/components/chakra/typography/span.pyi +0 -3
- reflex/components/chakra/typography/text.pyi +0 -3
- reflex/components/component.py +61 -22
- reflex/components/core/client_side_routing.pyi +0 -6
- reflex/components/core/upload.py +3 -1
- reflex/components/core/upload.pyi +0 -3
- reflex/components/el/element.pyi +0 -3
- reflex/components/el/elements/base.pyi +0 -3
- reflex/components/el/elements/forms.pyi +0 -39
- reflex/components/el/elements/inline.pyi +0 -84
- reflex/components/el/elements/media.pyi +0 -42
- reflex/components/el/elements/metadata.pyi +0 -15
- reflex/components/el/elements/other.pyi +0 -21
- reflex/components/el/elements/scripts.pyi +0 -9
- reflex/components/el/elements/sectioning.pyi +0 -45
- reflex/components/el/elements/tables.pyi +0 -30
- reflex/components/el/elements/typography.pyi +0 -45
- reflex/components/gridjs/datatable.pyi +0 -3
- reflex/components/lucide/icon.pyi +0 -3
- reflex/components/next/base.pyi +0 -3
- reflex/components/next/link.pyi +0 -3
- reflex/components/plotly/plotly.pyi +0 -6
- reflex/components/radix/primitives/accordion.pyi +0 -3
- reflex/components/radix/primitives/base.pyi +0 -6
- reflex/components/radix/primitives/drawer.pyi +0 -21
- reflex/components/radix/primitives/form.pyi +0 -18
- reflex/components/radix/primitives/progress.pyi +0 -9
- reflex/components/radix/primitives/slider.pyi +0 -15
- reflex/components/radix/themes/base.pyi +0 -6
- reflex/components/react_player/audio.pyi +0 -3
- reflex/components/react_player/react_player.pyi +0 -3
- reflex/components/react_player/video.pyi +0 -3
- reflex/components/recharts/cartesian.pyi +0 -57
- reflex/components/recharts/general.pyi +0 -12
- reflex/components/recharts/polar.pyi +0 -18
- reflex/components/recharts/recharts.pyi +0 -3
- reflex/constants/__init__.py +2 -0
- reflex/constants/base.py +5 -0
- reflex/constants/compiler.py +2 -0
- reflex/constants/installer.py +4 -2
- reflex/event.py +7 -6
- reflex/experimental/__init__.py +2 -0
- reflex/experimental/misc.py +12 -0
- reflex/model.py +1 -1
- reflex/reflex.py +0 -1
- reflex/utils/compat.py +43 -0
- reflex/utils/console.py +10 -1
- reflex/utils/export.py +1 -3
- reflex/utils/imports.py +14 -1
- reflex/utils/prerequisites.py +65 -41
- reflex/utils/processes.py +37 -0
- reflex/utils/serializers.py +14 -0
- reflex/utils/types.py +1 -1
- {reflex-0.4.7a3.dist-info → reflex-0.4.8a1.dist-info}/METADATA +1 -2
- {reflex-0.4.7a3.dist-info → reflex-0.4.8a1.dist-info}/RECORD +124 -122
- {reflex-0.4.7a3.dist-info → reflex-0.4.8a1.dist-info}/WHEEL +1 -1
- {reflex-0.4.7a3.dist-info → reflex-0.4.8a1.dist-info}/LICENSE +0 -0
- {reflex-0.4.7a3.dist-info → reflex-0.4.8a1.dist-info}/entry_points.txt +0 -0
reflex/utils/prerequisites.py
CHANGED
|
@@ -19,7 +19,7 @@ from datetime import datetime
|
|
|
19
19
|
from fileinput import FileInput
|
|
20
20
|
from pathlib import Path
|
|
21
21
|
from types import ModuleType
|
|
22
|
-
from typing import Callable, Optional
|
|
22
|
+
from typing import Callable, List, Optional
|
|
23
23
|
|
|
24
24
|
import httpx
|
|
25
25
|
import pkg_resources
|
|
@@ -35,6 +35,7 @@ from reflex.base import Base
|
|
|
35
35
|
from reflex.compiler import templates
|
|
36
36
|
from reflex.config import Config, get_config
|
|
37
37
|
from reflex.utils import console, path_ops, processes
|
|
38
|
+
from reflex.utils.format import format_library_name
|
|
38
39
|
|
|
39
40
|
CURRENTLY_INSTALLING_NODE = False
|
|
40
41
|
|
|
@@ -166,16 +167,13 @@ def get_bun_version() -> version.Version | None:
|
|
|
166
167
|
|
|
167
168
|
def get_install_package_manager() -> str | None:
|
|
168
169
|
"""Get the package manager executable for installation.
|
|
169
|
-
Currently
|
|
170
|
+
Currently, bun is used for installation only.
|
|
170
171
|
|
|
171
172
|
Returns:
|
|
172
173
|
The path to the package manager.
|
|
173
174
|
"""
|
|
174
|
-
|
|
175
|
-
if constants.IS_WINDOWS:
|
|
175
|
+
if constants.IS_WINDOWS and not constants.IS_WINDOWS_BUN_SUPPORTED_MACHINE:
|
|
176
176
|
return get_package_manager()
|
|
177
|
-
|
|
178
|
-
# On other platforms, we use bun.
|
|
179
177
|
return get_config().bun_path
|
|
180
178
|
|
|
181
179
|
|
|
@@ -227,11 +225,12 @@ def get_app(reload: bool = False) -> ModuleType:
|
|
|
227
225
|
return app
|
|
228
226
|
|
|
229
227
|
|
|
230
|
-
def get_compiled_app(reload: bool = False) -> ModuleType:
|
|
228
|
+
def get_compiled_app(reload: bool = False, export: bool = False) -> ModuleType:
|
|
231
229
|
"""Get the app module based on the default config after first compiling it.
|
|
232
230
|
|
|
233
231
|
Args:
|
|
234
232
|
reload: Re-import the app module from disk
|
|
233
|
+
export: Compile the app for export
|
|
235
234
|
|
|
236
235
|
Returns:
|
|
237
236
|
The compiled app based on the default config.
|
|
@@ -241,7 +240,7 @@ def get_compiled_app(reload: bool = False) -> ModuleType:
|
|
|
241
240
|
# For py3.8 and py3.9 compatibility when redis is used, we MUST add any decorator pages
|
|
242
241
|
# before compiling the app in a thread to avoid event loop error (REF-2172).
|
|
243
242
|
app._apply_decorated_pages()
|
|
244
|
-
app.compile_()
|
|
243
|
+
app.compile_(export=export)
|
|
245
244
|
return app_module
|
|
246
245
|
|
|
247
246
|
|
|
@@ -562,28 +561,37 @@ def init_reflex_json(project_hash: int | None):
|
|
|
562
561
|
path_ops.update_json_file(constants.Reflex.JSON, reflex_json)
|
|
563
562
|
|
|
564
563
|
|
|
565
|
-
def update_next_config(export=False):
|
|
564
|
+
def update_next_config(export=False, transpile_packages: Optional[List[str]] = None):
|
|
566
565
|
"""Update Next.js config from Reflex config.
|
|
567
566
|
|
|
568
567
|
Args:
|
|
569
568
|
export: if the method run during reflex export.
|
|
569
|
+
transpile_packages: list of packages to transpile via next.config.js.
|
|
570
570
|
"""
|
|
571
571
|
next_config_file = os.path.join(constants.Dirs.WEB, constants.Next.CONFIG_FILE)
|
|
572
572
|
|
|
573
|
-
next_config = _update_next_config(
|
|
573
|
+
next_config = _update_next_config(
|
|
574
|
+
get_config(), export=export, transpile_packages=transpile_packages
|
|
575
|
+
)
|
|
574
576
|
|
|
575
577
|
with open(next_config_file, "w") as file:
|
|
576
578
|
file.write(next_config)
|
|
577
579
|
file.write("\n")
|
|
578
580
|
|
|
579
581
|
|
|
580
|
-
def _update_next_config(
|
|
582
|
+
def _update_next_config(
|
|
583
|
+
config: Config, export: bool = False, transpile_packages: Optional[List[str]] = None
|
|
584
|
+
):
|
|
581
585
|
next_config = {
|
|
582
586
|
"basePath": config.frontend_path or "",
|
|
583
587
|
"compress": config.next_compression,
|
|
584
588
|
"reactStrictMode": True,
|
|
585
589
|
"trailingSlash": True,
|
|
586
590
|
}
|
|
591
|
+
if transpile_packages:
|
|
592
|
+
next_config["transpilePackages"] = list(
|
|
593
|
+
set((format_library_name(p) for p in transpile_packages))
|
|
594
|
+
)
|
|
587
595
|
if export:
|
|
588
596
|
next_config["output"] = "export"
|
|
589
597
|
next_config["distDir"] = constants.Dirs.STATIC
|
|
@@ -718,10 +726,10 @@ def install_bun():
|
|
|
718
726
|
Raises:
|
|
719
727
|
FileNotFoundError: If required packages are not found.
|
|
720
728
|
"""
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
729
|
+
if constants.IS_WINDOWS and not constants.IS_WINDOWS_BUN_SUPPORTED_MACHINE:
|
|
730
|
+
console.warn(
|
|
731
|
+
"Bun for Windows is currently only available for x86 64-bit Windows. Installation will fall back on npm."
|
|
732
|
+
)
|
|
725
733
|
|
|
726
734
|
# Skip if bun is already installed.
|
|
727
735
|
if os.path.exists(get_config().bun_path) and get_bun_version() == version.parse(
|
|
@@ -731,16 +739,25 @@ def install_bun():
|
|
|
731
739
|
return
|
|
732
740
|
|
|
733
741
|
# if unzip is installed
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
742
|
+
if constants.IS_WINDOWS:
|
|
743
|
+
processes.new_process(
|
|
744
|
+
["powershell", "-c", f"irm {constants.Bun.INSTALL_URL}.ps1|iex"],
|
|
745
|
+
env={"BUN_INSTALL": constants.Bun.ROOT_PATH},
|
|
746
|
+
shell=True,
|
|
747
|
+
run=True,
|
|
748
|
+
show_logs=console.is_debug(),
|
|
749
|
+
)
|
|
750
|
+
else:
|
|
751
|
+
unzip_path = path_ops.which("unzip")
|
|
752
|
+
if unzip_path is None:
|
|
753
|
+
raise FileNotFoundError("Reflex requires unzip to be installed.")
|
|
754
|
+
|
|
755
|
+
# Run the bun install script.
|
|
756
|
+
download_and_run(
|
|
757
|
+
constants.Bun.INSTALL_URL,
|
|
758
|
+
f"bun-v{constants.Bun.VERSION}",
|
|
759
|
+
BUN_INSTALL=constants.Bun.ROOT_PATH,
|
|
760
|
+
)
|
|
744
761
|
|
|
745
762
|
|
|
746
763
|
def _write_cached_procedure_file(payload: str, cache_file: str):
|
|
@@ -802,18 +819,22 @@ def install_frontend_packages(packages: set[str], config: Config):
|
|
|
802
819
|
Example:
|
|
803
820
|
>>> install_frontend_packages(["react", "react-dom"], get_config())
|
|
804
821
|
"""
|
|
805
|
-
#
|
|
806
|
-
|
|
822
|
+
# unsupported archs will use npm anyway. so we dont have to run npm twice
|
|
823
|
+
fallback_command = (
|
|
824
|
+
get_package_manager()
|
|
825
|
+
if constants.IS_WINDOWS and constants.IS_WINDOWS_BUN_SUPPORTED_MACHINE
|
|
826
|
+
else None
|
|
827
|
+
)
|
|
828
|
+
processes.run_process_with_fallback(
|
|
807
829
|
[get_install_package_manager(), "install", "--loglevel", "silly"],
|
|
830
|
+
fallback=fallback_command,
|
|
831
|
+
show_status_message="Installing base frontend packages",
|
|
808
832
|
cwd=constants.Dirs.WEB,
|
|
809
833
|
shell=constants.IS_WINDOWS,
|
|
810
834
|
)
|
|
811
835
|
|
|
812
|
-
processes.show_status("Installing base frontend packages", process)
|
|
813
|
-
|
|
814
836
|
if config.tailwind is not None:
|
|
815
|
-
|
|
816
|
-
process = processes.new_process(
|
|
837
|
+
processes.run_process_with_fallback(
|
|
817
838
|
[
|
|
818
839
|
get_install_package_manager(),
|
|
819
840
|
"add",
|
|
@@ -821,21 +842,21 @@ def install_frontend_packages(packages: set[str], config: Config):
|
|
|
821
842
|
constants.Tailwind.VERSION,
|
|
822
843
|
*((config.tailwind or {}).get("plugins", [])),
|
|
823
844
|
],
|
|
845
|
+
fallback=fallback_command,
|
|
846
|
+
show_status_message="Installing tailwind",
|
|
824
847
|
cwd=constants.Dirs.WEB,
|
|
825
848
|
shell=constants.IS_WINDOWS,
|
|
826
849
|
)
|
|
827
|
-
processes.show_status("Installing tailwind", process)
|
|
828
850
|
|
|
829
851
|
# Install custom packages defined in frontend_packages
|
|
830
852
|
if len(packages) > 0:
|
|
831
|
-
|
|
853
|
+
processes.run_process_with_fallback(
|
|
832
854
|
[get_install_package_manager(), "add", *packages],
|
|
855
|
+
fallback=fallback_command,
|
|
856
|
+
show_status_message="Installing frontend packages from config and components",
|
|
833
857
|
cwd=constants.Dirs.WEB,
|
|
834
858
|
shell=constants.IS_WINDOWS,
|
|
835
859
|
)
|
|
836
|
-
processes.show_status(
|
|
837
|
-
"Installing frontend packages from config and components", process
|
|
838
|
-
)
|
|
839
860
|
|
|
840
861
|
|
|
841
862
|
def needs_reinit(frontend: bool = True) -> bool:
|
|
@@ -856,12 +877,16 @@ def needs_reinit(frontend: bool = True) -> bool:
|
|
|
856
877
|
)
|
|
857
878
|
raise typer.Exit(1)
|
|
858
879
|
|
|
880
|
+
# Don't need to reinit if not running in frontend mode.
|
|
881
|
+
if not frontend:
|
|
882
|
+
return False
|
|
883
|
+
|
|
859
884
|
# Make sure the .reflex directory exists.
|
|
860
885
|
if not os.path.exists(constants.Reflex.DIR):
|
|
861
886
|
return True
|
|
862
887
|
|
|
863
888
|
# Make sure the .web directory exists in frontend mode.
|
|
864
|
-
if
|
|
889
|
+
if not os.path.exists(constants.Dirs.WEB):
|
|
865
890
|
return True
|
|
866
891
|
|
|
867
892
|
if constants.IS_WINDOWS:
|
|
@@ -938,9 +963,6 @@ def validate_frontend_dependencies(init=True):
|
|
|
938
963
|
)
|
|
939
964
|
raise typer.Exit(1)
|
|
940
965
|
|
|
941
|
-
if constants.IS_WINDOWS:
|
|
942
|
-
return
|
|
943
|
-
|
|
944
966
|
if init:
|
|
945
967
|
# we only need bun for package install on `reflex init`.
|
|
946
968
|
validate_bun()
|
|
@@ -1369,7 +1391,9 @@ def initialize_app(app_name: str, template: str | None = None):
|
|
|
1369
1391
|
else:
|
|
1370
1392
|
# Check if the template is a github repo.
|
|
1371
1393
|
if template.startswith("https://github.com"):
|
|
1372
|
-
template_url =
|
|
1394
|
+
template_url = (
|
|
1395
|
+
f"{template.strip('/').replace('.git', '')}/archive/main.zip"
|
|
1396
|
+
)
|
|
1373
1397
|
else:
|
|
1374
1398
|
console.error(f"Template `{template}` not found.")
|
|
1375
1399
|
raise typer.Exit(1)
|
reflex/utils/processes.py
CHANGED
|
@@ -287,3 +287,40 @@ def show_progress(message: str, process: subprocess.Popen, checkpoints: List[str
|
|
|
287
287
|
def atexit_handler():
|
|
288
288
|
"""Display a custom message with the current time when exiting an app."""
|
|
289
289
|
console.log("Reflex app stopped.")
|
|
290
|
+
|
|
291
|
+
|
|
292
|
+
def run_process_with_fallback(args, *, show_status_message, fallback=None, **kwargs):
|
|
293
|
+
"""Run subprocess and retry using fallback command if initial command fails.
|
|
294
|
+
|
|
295
|
+
Args:
|
|
296
|
+
args: A string, or a sequence of program arguments.
|
|
297
|
+
show_status_message: The status message to be displayed in the console.
|
|
298
|
+
fallback: The fallback command to run.
|
|
299
|
+
kwargs: Kwargs to pass to new_process function.
|
|
300
|
+
"""
|
|
301
|
+
|
|
302
|
+
def execute_process(process):
|
|
303
|
+
if not constants.IS_WINDOWS:
|
|
304
|
+
show_status(show_status_message, process)
|
|
305
|
+
else:
|
|
306
|
+
process.wait()
|
|
307
|
+
if process.returncode != 0:
|
|
308
|
+
error_output = process.stderr if process.stderr else process.stdout
|
|
309
|
+
error_message = f"Error occurred during subprocess execution: {' '.join(args)}\n{error_output.read() if error_output else ''}"
|
|
310
|
+
# Only show error in debug mode.
|
|
311
|
+
if console.is_debug():
|
|
312
|
+
console.error(error_message)
|
|
313
|
+
|
|
314
|
+
# retry with fallback command.
|
|
315
|
+
fallback_args = [fallback, *args[1:]] if fallback else None
|
|
316
|
+
console.warn(
|
|
317
|
+
f"There was an error running command: {args}. Falling back to: {fallback_args}."
|
|
318
|
+
)
|
|
319
|
+
if fallback_args:
|
|
320
|
+
process = new_process(fallback_args, **kwargs)
|
|
321
|
+
execute_process(process)
|
|
322
|
+
else:
|
|
323
|
+
show_status(show_status_message, process)
|
|
324
|
+
|
|
325
|
+
process = new_process(args, **kwargs)
|
|
326
|
+
execute_process(process)
|
reflex/utils/serializers.py
CHANGED
|
@@ -6,6 +6,7 @@ import json
|
|
|
6
6
|
import types as builtin_types
|
|
7
7
|
import warnings
|
|
8
8
|
from datetime import date, datetime, time, timedelta
|
|
9
|
+
from enum import Enum
|
|
9
10
|
from typing import Any, Callable, Dict, List, Set, Tuple, Type, Union, get_type_hints
|
|
10
11
|
|
|
11
12
|
from reflex.base import Base
|
|
@@ -232,6 +233,19 @@ def serialize_datetime(dt: Union[date, datetime, time, timedelta]) -> str:
|
|
|
232
233
|
return str(dt)
|
|
233
234
|
|
|
234
235
|
|
|
236
|
+
@serializer
|
|
237
|
+
def serialize_enum(en: Enum) -> str:
|
|
238
|
+
"""Serialize a enum to a JSON string.
|
|
239
|
+
|
|
240
|
+
Args:
|
|
241
|
+
en: The enum to serialize.
|
|
242
|
+
|
|
243
|
+
Returns:
|
|
244
|
+
The serialized enum.
|
|
245
|
+
"""
|
|
246
|
+
return en.value
|
|
247
|
+
|
|
248
|
+
|
|
235
249
|
@serializer
|
|
236
250
|
def serialize_color(color: Color) -> str:
|
|
237
251
|
"""Serialize a color.
|
reflex/utils/types.py
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: reflex
|
|
3
|
-
Version: 0.4.
|
|
3
|
+
Version: 0.4.8a1
|
|
4
4
|
Summary: Web apps in pure Python.
|
|
5
5
|
Home-page: https://reflex.dev
|
|
6
6
|
License: Apache-2.0
|
|
@@ -15,7 +15,6 @@ Classifier: Programming Language :: Python :: 3.8
|
|
|
15
15
|
Classifier: Programming Language :: Python :: 3.9
|
|
16
16
|
Classifier: Programming Language :: Python :: 3.10
|
|
17
17
|
Classifier: Programming Language :: Python :: 3.11
|
|
18
|
-
Classifier: Programming Language :: Python :: 3.12
|
|
19
18
|
Requires-Dist: alembic (>=1.11.1,<2.0)
|
|
20
19
|
Requires-Dist: build (>=1.0.3,<2.0)
|
|
21
20
|
Requires-Dist: charset-normalizer (>=3.3.2,<4.0)
|