CLI script to maintain Chakra backed components in rx namespace in older apps (#2322)
This commit is contained in:
parent
ea2a5904f2
commit
a4ee985509
@ -100,6 +100,9 @@ def _init(
|
|||||||
# Migrate Pynecone projects to Reflex.
|
# Migrate Pynecone projects to Reflex.
|
||||||
prerequisites.migrate_to_reflex()
|
prerequisites.migrate_to_reflex()
|
||||||
|
|
||||||
|
if prerequisites.should_show_rx_chakra_migration_instructions():
|
||||||
|
prerequisites.show_rx_chakra_migration_instructions()
|
||||||
|
|
||||||
# Initialize the .gitignore.
|
# Initialize the .gitignore.
|
||||||
prerequisites.initialize_gitignore()
|
prerequisites.initialize_gitignore()
|
||||||
|
|
||||||
@ -336,6 +339,7 @@ def logout(
|
|||||||
|
|
||||||
|
|
||||||
db_cli = typer.Typer()
|
db_cli = typer.Typer()
|
||||||
|
script_cli = typer.Typer()
|
||||||
|
|
||||||
|
|
||||||
def _skip_compile():
|
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()
|
@cli.command()
|
||||||
def deploy(
|
def deploy(
|
||||||
key: Optional[str] = typer.Option(
|
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(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(
|
cli.add_typer(
|
||||||
deployments_cli,
|
deployments_cli,
|
||||||
name="deployments",
|
name="deployments",
|
||||||
|
@ -4,6 +4,7 @@ from __future__ import annotations
|
|||||||
|
|
||||||
import glob
|
import glob
|
||||||
import importlib
|
import importlib
|
||||||
|
import inspect
|
||||||
import json
|
import json
|
||||||
import os
|
import os
|
||||||
import platform
|
import platform
|
||||||
@ -25,6 +26,7 @@ from alembic.util.exc import CommandError
|
|||||||
from packaging import version
|
from packaging import version
|
||||||
from redis.asyncio import Redis
|
from redis.asyncio import Redis
|
||||||
|
|
||||||
|
import reflex
|
||||||
from reflex import constants, model
|
from reflex import constants, model
|
||||||
from reflex.compiler import templates
|
from reflex.compiler import templates
|
||||||
from reflex.config import Config, get_config
|
from reflex.config import Config, get_config
|
||||||
@ -938,6 +940,110 @@ def prompt_for_template() -> constants.Templates.Kind:
|
|||||||
return constants.Templates.Kind(template)
|
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():
|
def migrate_to_reflex():
|
||||||
"""Migration from Pynecone to Reflex."""
|
"""Migration from Pynecone to Reflex."""
|
||||||
# Check if the old config file exists.
|
# Check if the old config file exists.
|
||||||
|
13
scripts/migrate_project_to_rx_chakra.py
Normal file
13
scripts/migrate_project_to_rx_chakra.py
Normal 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()
|
Loading…
Reference in New Issue
Block a user