Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Lazy import modules in reflex #2144

Merged
merged 12 commits into from
Nov 14, 2023
350 changes: 310 additions & 40 deletions reflex/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,44 +4,314 @@
To signal to typecheckers that something should be reexported,
we use the Flask "import name as name" syntax.
"""
import importlib
from typing import Type

from . import el as el
from .admin import AdminDash as AdminDash
from .app import App as App
from .app import UploadFile as UploadFile
from .base import Base as Base
from .compiler.utils import get_asset_path
from .components import *
from .components.component import custom_component as memo
from .components.graphing import recharts as recharts
from .config import Config as Config
from .config import DBConfig as DBConfig
from .constants import Env as Env
from .event import EventChain as EventChain
from .event import FileUpload as upload_files
from .event import background as background
from .event import call_script as call_script
from .event import clear_local_storage as clear_local_storage
from .event import console_log as console_log
from .event import download as download
from .event import prevent_default as prevent_default
from .event import redirect as redirect
from .event import remove_cookie as remove_cookie
from .event import remove_local_storage as remove_local_storage
from .event import set_clipboard as set_clipboard
from .event import set_focus as set_focus
from .event import set_value as set_value
from .event import stop_propagation as stop_propagation
from .event import window_alert as window_alert
from .middleware import Middleware as Middleware
from .model import Model as Model
from .model import session as session
from .page import page as page
from .state import ComputedVar as var
from .state import Cookie as Cookie
from .state import LocalStorage as LocalStorage
from .state import State as State
from .style import color_mode as color_mode
from .style import toggle_color_mode as toggle_color_mode
from .vars import Var as Var
from .vars import cached_var as cached_var
from reflex.page import page as page
from reflex.utils.format import to_snake_case

_ALL_COMPONENTS = [
"Accordion",
"AccordionButton",
"AccordionIcon",
"AccordionItem",
"AccordionPanel",
"Alert",
"AlertDescription",
"AlertDialog",
"AlertDialogBody",
"AlertDialogContent",
"AlertDialogFooter",
"AlertDialogHeader",
"AlertDialogOverlay",
"AlertIcon",
"AlertTitle",
"AspectRatio",
"Audio",
"Avatar",
"AvatarBadge",
"AvatarGroup",
"Badge",
"Box",
"Breadcrumb",
"BreadcrumbItem",
"BreadcrumbLink",
"BreadcrumbSeparator",
"Button",
"ButtonGroup",
"Card",
"CardBody",
"CardFooter",
"CardHeader",
"Center",
"Checkbox",
"CheckboxGroup",
"CircularProgress",
"CircularProgressLabel",
"Circle",
"Code",
"CodeBlock",
"Collapse",
"ColorModeButton",
"ColorModeIcon",
"ColorModeSwitch",
"Component",
"Cond",
"Container",
"DataTable",
"DataEditor",
"DebounceInput",
"Divider",
"Drawer",
"DrawerBody",
"DrawerCloseButton",
"DrawerContent",
"DrawerFooter",
"DrawerHeader",
"DrawerOverlay",
"Editable",
"EditableInput",
"EditablePreview",
"EditableTextarea",
"Editor",
"Email",
"Fade",
"Flex",
"Foreach",
"Form",
"FormControl",
"FormErrorMessage",
"FormHelperText",
"FormLabel",
"Fragment",
"Grid",
"GridItem",
"Heading",
"Highlight",
"Hstack",
"Html",
"Icon",
"IconButton",
"Image",
"Input",
"InputGroup",
"InputLeftAddon",
"InputLeftElement",
"InputRightAddon",
"InputRightElement",
"Kbd",
"Link",
"LinkBox",
"LinkOverlay",
"List",
"ListItem",
"Markdown",
"Menu",
"MenuButton",
"MenuDivider",
"MenuGroup",
"MenuItem",
"MenuItemOption",
"MenuList",
"MenuOptionGroup",
"Modal",
"ModalBody",
"ModalCloseButton",
"ModalContent",
"ModalFooter",
"ModalHeader",
"ModalOverlay",
"Moment",
"MultiSelect",
"MultiSelectOption",
"NextLink",
"NumberDecrementStepper",
"NumberIncrementStepper",
"NumberInput",
"NumberInputField",
"NumberInputStepper",
"Option",
"OrderedList",
"Password",
"PinInput",
"PinInputField",
"Plotly",
"Popover",
"PopoverAnchor",
"PopoverArrow",
"PopoverBody",
"PopoverCloseButton",
"PopoverContent",
"PopoverFooter",
"PopoverHeader",
"PopoverTrigger",
"Progress",
"Radio",
"RadioGroup",
"RangeSlider",
"RangeSliderFilledTrack",
"RangeSliderThumb",
"RangeSliderTrack",
"ResponsiveGrid",
"ScaleFade",
"Script",
"Select",
"Skeleton",
"SkeletonCircle",
"SkeletonText",
"Slide",
"SlideFade",
"Slider",
"SliderFilledTrack",
"SliderMark",
"SliderThumb",
"SliderTrack",
"Spacer",
"Span",
"Spinner",
"Square",
"Stack",
"Stat",
"StatArrow",
"StatGroup",
"StatHelpText",
"StatLabel",
"StatArrow",
"StatGroup",
"StatHelpText",
"StatLabel",
"StatNumber",
"Step",
"StepDescription",
"StepIcon",
"StepIndicator",
"StepNumber",
"StepSeparator",
"StepStatus",
"StepTitle",
"Stepper",
"Switch",
"Tab",
"TabList",
"TabPanel",
"TabPanels",
"Table",
"TableCaption",
"TableContainer",
"Tabs",
"Tag",
"TagCloseButton",
"TagLabel",
"TagLeftIcon",
"TagRightIcon",
"Tbody",
"Td",
"Text",
"TextArea",
"Tfoot",
"Th",
"Thead",
"Tooltip",
"Tr",
"UnorderedList",
"Upload",
"Video",
"VisuallyHidden",
"Vstack",
"Wrap",
"WrapItem",
]

_ALL_COMPONENTS += [to_snake_case(component) for component in _ALL_COMPONENTS]
_ALL_COMPONENTS += [
"components",
"desktop_only",
"mobile_only",
"tablet_only",
"mobile_and_tablet",
"tablet_and_desktop",
"selected_files",
"clear_selected_files",
"EditorOptions",
]

_MAPPING = {
"reflex.admin": ["admin", "AdminDash"],
"reflex.app": ["app", "App", "UploadFile"],
"reflex.base": ["base", "Base"],
"reflex.compiler": ["compiler"],
"reflex.compiler.utils": ["get_asset_path"],
"reflex.components": _ALL_COMPONENTS,
"reflex.components.component": ["memo"],
"reflex.components.graphing": ["recharts"],
"reflex.config": ["config", "Config", "DBConfig"],
"reflex.constants": ["constants", "Env"],
"reflex.el": ["el"],
"reflex.event": [
"event",
"EventChain",
"background",
"call_script",
"clear_local_storage",
"console_log",
"download",
"prevent_default",
"redirect",
"remove_cookie",
"remove_local_storage",
"set_clipboard",
"set_focus",
"set_value",
"stop_propagation",
"upload_files",
"window_alert",
],
"reflex.middleware": ["middleware", "Middleware"],
"reflex.model": ["model", "session", "Model"],
"reflex.page": ["page"],
"reflex.route": ["route"],
"reflex.state": ["state", "var", "Cookie", "LocalStorage", "State"],
"reflex.style": ["style", "color_mode", "toggle_color_mode"],
"reflex.testing": ["testing"],
"reflex.utils": ["utils"],
"reflex.vars": ["vars", "cached_var", "Var"],
}
_MAPPING = {value: key for key, values in _MAPPING.items() for value in values}


def _removeprefix(text, prefix):
return text[text.startswith(prefix) and len(prefix) :]


__all__ = [_removeprefix(mod, "reflex.") for mod in _MAPPING]


def __getattr__(name: str) -> Type:
"""Lazy load all modules.

Args:
name: name of the module to load.

Returns:
The module or the attribute of the module.

Raises:
AttributeError: If the module or the attribute does not exist.
"""
try:
# Check for import of a module that is not in the mapping.
if name not in _MAPPING:
# If the name does not start with reflex, add it.
if not name.startswith("reflex") and name != "__all__":
name = f"reflex.{name}"
return importlib.import_module(name)

# Import the module.
module = importlib.import_module(_MAPPING[name])

# Get the attribute from the module if the name is not the module itself.
return (
getattr(module, name) if name != _MAPPING[name].rsplit(".")[-1] else module
)
except ModuleNotFoundError:
raise AttributeError(f"module 'reflex' has no attribute {name}") from None
Loading
Loading