CLI script to maintain Chakra backed components in rx namespace in older apps (#2322)

This commit is contained in:
jackie-pc 2024-02-08 11:12:20 -08:00 committed by GitHub
parent ea2a5904f2
commit a4ee985509
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 135 additions and 0 deletions

View File

@ -100,6 +100,9 @@ def _init(
# Migrate Pynecone projects to Reflex.
prerequisites.migrate_to_reflex()
if prerequisites.should_show_rx_chakra_migration_instructions():
prerequisites.show_rx_chakra_migration_instructions()
# Initialize the .gitignore.
prerequisites.initialize_gitignore()
@ -336,6 +339,7 @@ def logout(
db_cli = typer.Typer()
script_cli = typer.Typer()
def _skip_compile():
@ -414,6 +418,17 @@ def makemigrations(
)
@script_cli.command(
name="keep-chakra",
help="Change all rx.<component> references to rx.chakra.<component>, to preserve Chakra UI usage.",
)
def keep_chakra():
"""Change all rx.<component> references to rx.chakra.<component>, to preserve Chakra UI usage."""
from reflex.utils import prerequisites
prerequisites.migrate_to_rx_chakra()
@cli.command()
def deploy(
key: Optional[str] = typer.Option(
@ -555,6 +570,7 @@ def demo(
cli.add_typer(db_cli, name="db", help="Subcommands for managing the database schema.")
cli.add_typer(script_cli, name="script", help="Subcommands running helper scripts.")
cli.add_typer(
deployments_cli,
name="deployments",

View File

@ -4,6 +4,7 @@ from __future__ import annotations
import glob
import importlib
import inspect
import json
import os
import platform
@ -25,6 +26,7 @@ from alembic.util.exc import CommandError
from packaging import version
from redis.asyncio import Redis
import reflex
from reflex import constants, model
from reflex.compiler import templates
from reflex.config import Config, get_config
@ -938,6 +940,110 @@ def prompt_for_template() -> constants.Templates.Kind:
return constants.Templates.Kind(template)
def should_show_rx_chakra_migration_instructions() -> bool:
"""Should we show the migration instructions for rx.chakra.* => rx.*?.
Returns:
bool: True if we should show the migration instructions.
"""
if os.getenv("REFLEX_PROMPT_MIGRATE_TO_RX_CHAKRA") == "yes":
return True
with open(constants.Dirs.REFLEX_JSON, "r") as f:
data = json.load(f)
existing_init_reflex_version = data.get("version", None)
if existing_init_reflex_version is None:
# They clone a reflex app from git for the first time.
# That app may or may not be 0.4 compatible.
# So let's just show these instructions THIS TIME.
return True
if constants.Reflex.VERSION < "0.4":
return False
else:
return existing_init_reflex_version < "0.4"
def show_rx_chakra_migration_instructions():
"""Show the migration instructions for rx.chakra.* => rx.*."""
console.log(
"Prior to reflex 0.4.0, rx.* components are based on Chakra UI. They are now based on Radix UI. To stick to Chakra UI, use rx.chakra.*."
)
console.log("")
console.log(
"[bold]Run `reflex script keep-chakra` to automatically update your app."
)
console.log("")
console.log("For more details, please see https://TODO") # TODO add link to docs
def migrate_to_rx_chakra():
"""Migrate rx.button => r.chakra.button, etc."""
file_pattern = os.path.join(get_config().app_name, "**/*.py")
file_list = glob.glob(file_pattern, recursive=True)
# Populate with all rx.<x> components that have been moved to rx.chakra.<x>
patterns = {
rf"\brx\.{name}\b": f"rx.chakra.{name}"
for name in _get_rx_chakra_component_to_migrate()
}
for file_path in file_list:
with FileInput(file_path, inplace=True) as file:
for _line_num, line in enumerate(file):
for old, new in patterns.items():
line = re.sub(old, new, line)
print(line, end="")
def _get_rx_chakra_component_to_migrate() -> set[str]:
from reflex.components import ChakraComponent
rx_chakra_names = set(dir(reflex.chakra))
names_to_migrate = set()
whitelist = {
"CodeBlock",
"ColorModeIcon",
"MultiSelect",
"MultiSelectOption",
"base",
"code_block",
"color_mode_cond",
"color_mode_icon",
"multi_select",
"multi_select_option",
}
for rx_chakra_name in sorted(rx_chakra_names):
if rx_chakra_name.startswith("_"):
continue
rx_chakra_object = getattr(reflex.chakra, rx_chakra_name)
try:
if (
inspect.ismethod(rx_chakra_object)
and inspect.isclass(rx_chakra_object.__self__)
and issubclass(rx_chakra_object.__self__, ChakraComponent)
):
names_to_migrate.add(rx_chakra_name)
elif inspect.isclass(rx_chakra_object) and issubclass(
rx_chakra_object, ChakraComponent
):
names_to_migrate.add(rx_chakra_name)
pass
else:
# For the given rx.chakra.<x>, does rx.<x> exist?
# And of these, should we include in migration?
if hasattr(reflex, rx_chakra_name) and rx_chakra_name in whitelist:
names_to_migrate.add(rx_chakra_name)
except Exception:
raise
return names_to_migrate
def migrate_to_reflex():
"""Migration from Pynecone to Reflex."""
# Check if the old config file exists.

View File

@ -0,0 +1,13 @@
"""Migrate project to rx.chakra. I.e. switch usage of rx.<component> to rx.chakra.<component>."""
import argparse
if __name__ == "__main__":
# parse args just for the help message (-h, etc)
parser = argparse.ArgumentParser(
description="Migrate project to rx.chakra. I.e. switch usage of rx.<component> to rx.chakra.<component>."
)
args = parser.parse_args()
from reflex.utils.prerequisites import migrate_to_rx_chakra
migrate_to_rx_chakra()