Merge branch 'main' into lendemor/add_PGH_rule
This commit is contained in:
commit
2cb39ae27f
1
.gitignore
vendored
1
.gitignore
vendored
@ -4,6 +4,7 @@ assets/external/*
|
|||||||
dist/*
|
dist/*
|
||||||
examples/
|
examples/
|
||||||
.web
|
.web
|
||||||
|
.states
|
||||||
.idea
|
.idea
|
||||||
.vscode
|
.vscode
|
||||||
.coverage
|
.coverage
|
||||||
|
@ -408,7 +408,7 @@ export const connect = async (
|
|||||||
socket.current = io(endpoint.href, {
|
socket.current = io(endpoint.href, {
|
||||||
path: endpoint["pathname"],
|
path: endpoint["pathname"],
|
||||||
transports: transports,
|
transports: transports,
|
||||||
protocols: env.TEST_MODE ? undefined : [reflexEnvironment.version],
|
protocols: [reflexEnvironment.version],
|
||||||
autoUnref: false,
|
autoUnref: false,
|
||||||
});
|
});
|
||||||
// Ensure undefined fields in events are sent as null instead of removed
|
// Ensure undefined fields in events are sent as null instead of removed
|
||||||
|
@ -405,7 +405,31 @@ class App(MiddlewareMixin, LifespanMixin):
|
|||||||
self.sio.register_namespace(self.event_namespace)
|
self.sio.register_namespace(self.event_namespace)
|
||||||
# Mount the socket app with the API.
|
# Mount the socket app with the API.
|
||||||
if self.api:
|
if self.api:
|
||||||
self.api.mount(str(constants.Endpoint.EVENT), socket_app)
|
|
||||||
|
class HeaderMiddleware:
|
||||||
|
def __init__(self, app):
|
||||||
|
self.app = app
|
||||||
|
|
||||||
|
async def __call__(self, scope, receive, send):
|
||||||
|
original_send = send
|
||||||
|
|
||||||
|
async def modified_send(message):
|
||||||
|
headers = dict(scope["headers"])
|
||||||
|
protocol_key = b"sec-websocket-protocol"
|
||||||
|
if (
|
||||||
|
message["type"] == "websocket.accept"
|
||||||
|
and protocol_key in headers
|
||||||
|
):
|
||||||
|
message["headers"] = [
|
||||||
|
*message.get("headers", []),
|
||||||
|
(b"sec-websocket-protocol", headers[protocol_key]),
|
||||||
|
]
|
||||||
|
return await original_send(message)
|
||||||
|
|
||||||
|
return await self.app(scope, receive, modified_send)
|
||||||
|
|
||||||
|
socket_app_with_headers = HeaderMiddleware(socket_app)
|
||||||
|
self.api.mount(str(constants.Endpoint.EVENT), socket_app_with_headers)
|
||||||
|
|
||||||
# Check the exception handlers
|
# Check the exception handlers
|
||||||
self._validate_exception_handlers()
|
self._validate_exception_handlers()
|
||||||
|
@ -490,6 +490,9 @@ class EnvironmentVariables:
|
|||||||
# The working directory for the next.js commands.
|
# The working directory for the next.js commands.
|
||||||
REFLEX_WEB_WORKDIR: EnvVar[Path] = env_var(Path(constants.Dirs.WEB))
|
REFLEX_WEB_WORKDIR: EnvVar[Path] = env_var(Path(constants.Dirs.WEB))
|
||||||
|
|
||||||
|
# The working directory for the states directory.
|
||||||
|
REFLEX_STATES_WORKDIR: EnvVar[Path] = env_var(Path(constants.Dirs.STATES))
|
||||||
|
|
||||||
# Path to the alembic config file
|
# Path to the alembic config file
|
||||||
ALEMBIC_CONFIG: EnvVar[ExistingPath] = env_var(Path(constants.ALEMBIC_CONFIG))
|
ALEMBIC_CONFIG: EnvVar[ExistingPath] = env_var(Path(constants.ALEMBIC_CONFIG))
|
||||||
|
|
||||||
|
@ -52,7 +52,7 @@ class Dirs(SimpleNamespace):
|
|||||||
# The name of the postcss config file.
|
# The name of the postcss config file.
|
||||||
POSTCSS_JS = "postcss.config.js"
|
POSTCSS_JS = "postcss.config.js"
|
||||||
# The name of the states directory.
|
# The name of the states directory.
|
||||||
STATES = "states"
|
STATES = ".states"
|
||||||
|
|
||||||
|
|
||||||
class Reflex(SimpleNamespace):
|
class Reflex(SimpleNamespace):
|
||||||
|
@ -39,7 +39,14 @@ class GitIgnore(SimpleNamespace):
|
|||||||
# The gitignore file.
|
# The gitignore file.
|
||||||
FILE = Path(".gitignore")
|
FILE = Path(".gitignore")
|
||||||
# Files to gitignore.
|
# Files to gitignore.
|
||||||
DEFAULTS = {Dirs.WEB, "*.db", "__pycache__/", "*.py[cod]", "assets/external/"}
|
DEFAULTS = {
|
||||||
|
Dirs.WEB,
|
||||||
|
Dirs.STATES,
|
||||||
|
"*.db",
|
||||||
|
"__pycache__/",
|
||||||
|
"*.py[cod]",
|
||||||
|
"assets/external/",
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
class RequirementsTxt(SimpleNamespace):
|
class RequirementsTxt(SimpleNamespace):
|
||||||
|
@ -3046,7 +3046,7 @@ def is_serializable(value: Any) -> bool:
|
|||||||
|
|
||||||
def reset_disk_state_manager():
|
def reset_disk_state_manager():
|
||||||
"""Reset the disk state manager."""
|
"""Reset the disk state manager."""
|
||||||
states_directory = prerequisites.get_web_dir() / constants.Dirs.STATES
|
states_directory = prerequisites.get_states_dir()
|
||||||
if states_directory.exists():
|
if states_directory.exists():
|
||||||
for path in states_directory.iterdir():
|
for path in states_directory.iterdir():
|
||||||
path.unlink()
|
path.unlink()
|
||||||
@ -3094,7 +3094,7 @@ class StateManagerDisk(StateManager):
|
|||||||
Returns:
|
Returns:
|
||||||
The states directory.
|
The states directory.
|
||||||
"""
|
"""
|
||||||
return prerequisites.get_web_dir() / constants.Dirs.STATES
|
return prerequisites.get_states_dir()
|
||||||
|
|
||||||
def _purge_expired_states(self):
|
def _purge_expired_states(self):
|
||||||
"""Purge expired states from the disk."""
|
"""Purge expired states from the disk."""
|
||||||
|
@ -307,7 +307,7 @@ def run_granian_backend(host, port, loglevel: LogLevel):
|
|||||||
log_level=LogLevels(loglevel.value),
|
log_level=LogLevels(loglevel.value),
|
||||||
reload=True,
|
reload=True,
|
||||||
reload_paths=get_reload_dirs(),
|
reload_paths=get_reload_dirs(),
|
||||||
reload_ignore_dirs=[".web"],
|
reload_ignore_dirs=[".web", ".states"],
|
||||||
).serve()
|
).serve()
|
||||||
except ImportError:
|
except ImportError:
|
||||||
console.error(
|
console.error(
|
||||||
@ -467,19 +467,19 @@ def output_system_info():
|
|||||||
|
|
||||||
system = platform.system()
|
system = platform.system()
|
||||||
|
|
||||||
|
fnm_info = f"[FNM {prerequisites.get_fnm_version()} (Expected: {constants.Fnm.VERSION}) (PATH: {constants.Fnm.EXE})]"
|
||||||
|
|
||||||
if system != "Windows" or (
|
if system != "Windows" or (
|
||||||
system == "Windows" and prerequisites.is_windows_bun_supported()
|
system == "Windows" and prerequisites.is_windows_bun_supported()
|
||||||
):
|
):
|
||||||
dependencies.extend(
|
dependencies.extend(
|
||||||
[
|
[
|
||||||
f"[FNM {prerequisites.get_fnm_version()} (Expected: {constants.Fnm.VERSION}) (PATH: {constants.Fnm.EXE})]",
|
fnm_info,
|
||||||
f"[Bun {prerequisites.get_bun_version()} (Expected: {constants.Bun.VERSION}) (PATH: {config.bun_path})]",
|
f"[Bun {prerequisites.get_bun_version()} (Expected: {constants.Bun.VERSION}) (PATH: {path_ops.get_bun_path()})]",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
dependencies.append(
|
dependencies.append(fnm_info)
|
||||||
f"[FNM {prerequisites.get_fnm_version()} (Expected: {constants.Fnm.VERSION}) (PATH: {constants.Fnm.EXE})]",
|
|
||||||
)
|
|
||||||
|
|
||||||
if system == "Linux":
|
if system == "Linux":
|
||||||
import distro
|
import distro
|
||||||
|
@ -9,7 +9,7 @@ import shutil
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
from reflex import constants
|
from reflex import constants
|
||||||
from reflex.config import environment
|
from reflex.config import environment, get_config
|
||||||
|
|
||||||
# Shorthand for join.
|
# Shorthand for join.
|
||||||
join = os.linesep.join
|
join = os.linesep.join
|
||||||
@ -118,7 +118,7 @@ def ln(src: str | Path, dest: str | Path, overwrite: bool = False) -> bool:
|
|||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
def which(program: str | Path) -> str | Path | None:
|
def which(program: str | Path) -> Path | None:
|
||||||
"""Find the path to an executable.
|
"""Find the path to an executable.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
@ -127,7 +127,8 @@ def which(program: str | Path) -> str | Path | None:
|
|||||||
Returns:
|
Returns:
|
||||||
The path to the executable.
|
The path to the executable.
|
||||||
"""
|
"""
|
||||||
return shutil.which(str(program))
|
which_result = shutil.which(program)
|
||||||
|
return Path(which_result) if which_result else None
|
||||||
|
|
||||||
|
|
||||||
def use_system_node() -> bool:
|
def use_system_node() -> bool:
|
||||||
@ -156,12 +157,12 @@ def get_node_bin_path() -> Path | None:
|
|||||||
"""
|
"""
|
||||||
bin_path = Path(constants.Node.BIN_PATH)
|
bin_path = Path(constants.Node.BIN_PATH)
|
||||||
if not bin_path.exists():
|
if not bin_path.exists():
|
||||||
str_path = which("node")
|
path = which("node")
|
||||||
return Path(str_path).parent.resolve() if str_path else None
|
return path.parent.absolute() if path else None
|
||||||
return bin_path.resolve()
|
return bin_path.absolute()
|
||||||
|
|
||||||
|
|
||||||
def get_node_path() -> str | None:
|
def get_node_path() -> Path | None:
|
||||||
"""Get the node binary path.
|
"""Get the node binary path.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
@ -169,9 +170,8 @@ def get_node_path() -> str | None:
|
|||||||
"""
|
"""
|
||||||
node_path = Path(constants.Node.PATH)
|
node_path = Path(constants.Node.PATH)
|
||||||
if use_system_node() or not node_path.exists():
|
if use_system_node() or not node_path.exists():
|
||||||
system_node_path = which("node")
|
node_path = which("node")
|
||||||
return str(system_node_path) if system_node_path else None
|
return node_path
|
||||||
return str(node_path)
|
|
||||||
|
|
||||||
|
|
||||||
def get_npm_path() -> Path | None:
|
def get_npm_path() -> Path | None:
|
||||||
@ -182,11 +182,22 @@ def get_npm_path() -> Path | None:
|
|||||||
"""
|
"""
|
||||||
npm_path = Path(constants.Node.NPM_PATH)
|
npm_path = Path(constants.Node.NPM_PATH)
|
||||||
if use_system_node() or not npm_path.exists():
|
if use_system_node() or not npm_path.exists():
|
||||||
system_npm_path = which("npm")
|
npm_path = which("npm")
|
||||||
npm_path = Path(system_npm_path) if system_npm_path else None
|
|
||||||
return npm_path.absolute() if npm_path else None
|
return npm_path.absolute() if npm_path else None
|
||||||
|
|
||||||
|
|
||||||
|
def get_bun_path() -> Path | None:
|
||||||
|
"""Get bun binary path.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
The path to the bun binary file.
|
||||||
|
"""
|
||||||
|
bun_path = get_config().bun_path
|
||||||
|
if use_system_bun() or not bun_path.exists():
|
||||||
|
bun_path = which("bun")
|
||||||
|
return bun_path.absolute() if bun_path else None
|
||||||
|
|
||||||
|
|
||||||
def update_json_file(file_path: str | Path, update_dict: dict[str, int | str]):
|
def update_json_file(file_path: str | Path, update_dict: dict[str, int | str]):
|
||||||
"""Update the contents of a json file.
|
"""Update the contents of a json file.
|
||||||
|
|
||||||
@ -196,6 +207,9 @@ def update_json_file(file_path: str | Path, update_dict: dict[str, int | str]):
|
|||||||
"""
|
"""
|
||||||
fp = Path(file_path)
|
fp = Path(file_path)
|
||||||
|
|
||||||
|
# Create the parent directory if it doesn't exist.
|
||||||
|
fp.parent.mkdir(parents=True, exist_ok=True)
|
||||||
|
|
||||||
# Create the file if it doesn't exist.
|
# Create the file if it doesn't exist.
|
||||||
fp.touch(exist_ok=True)
|
fp.touch(exist_ok=True)
|
||||||
|
|
||||||
|
@ -87,6 +87,17 @@ def get_web_dir() -> Path:
|
|||||||
return environment.REFLEX_WEB_WORKDIR.get()
|
return environment.REFLEX_WEB_WORKDIR.get()
|
||||||
|
|
||||||
|
|
||||||
|
def get_states_dir() -> Path:
|
||||||
|
"""Get the working directory for the states.
|
||||||
|
|
||||||
|
Can be overridden with REFLEX_STATES_WORKDIR.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
The working directory.
|
||||||
|
"""
|
||||||
|
return environment.REFLEX_STATES_WORKDIR.get()
|
||||||
|
|
||||||
|
|
||||||
def check_latest_package_version(package_name: str):
|
def check_latest_package_version(package_name: str):
|
||||||
"""Check if the latest version of the package is installed.
|
"""Check if the latest version of the package is installed.
|
||||||
|
|
||||||
@ -194,10 +205,14 @@ def get_bun_version() -> version.Version | None:
|
|||||||
Returns:
|
Returns:
|
||||||
The version of bun.
|
The version of bun.
|
||||||
"""
|
"""
|
||||||
|
bun_path = path_ops.get_bun_path()
|
||||||
|
if bun_path is None:
|
||||||
|
return None
|
||||||
try:
|
try:
|
||||||
# Run the bun -v command and capture the output
|
# Run the bun -v command and capture the output
|
||||||
result = processes.new_process([str(get_config().bun_path), "-v"], run=True)
|
result = processes.new_process([str(get_config().bun_path), "-v"], run=True)
|
||||||
return version.parse(result.stdout) # pyright: ignore [reportArgumentType]
|
result = processes.new_process([str(get_config().bun_path), "-v"], run=True)
|
||||||
|
return version.parse(str(result.stdout)) # pyright: ignore [reportArgumentType]
|
||||||
except FileNotFoundError:
|
except FileNotFoundError:
|
||||||
return None
|
return None
|
||||||
except version.InvalidVersion as e:
|
except version.InvalidVersion as e:
|
||||||
@ -1051,9 +1066,7 @@ def install_bun():
|
|||||||
)
|
)
|
||||||
|
|
||||||
# Skip if bun is already installed.
|
# Skip if bun is already installed.
|
||||||
if Path(get_config().bun_path).exists() and get_bun_version() == version.parse(
|
if get_bun_version() == version.parse(constants.Bun.VERSION):
|
||||||
constants.Bun.VERSION
|
|
||||||
):
|
|
||||||
console.debug("Skipping bun installation as it is already installed.")
|
console.debug("Skipping bun installation as it is already installed.")
|
||||||
return
|
return
|
||||||
|
|
||||||
@ -1074,8 +1087,7 @@ def install_bun():
|
|||||||
show_logs=console.is_debug(),
|
show_logs=console.is_debug(),
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
unzip_path = path_ops.which("unzip")
|
if path_ops.which("unzip") is None:
|
||||||
if unzip_path is None:
|
|
||||||
raise SystemPackageMissingError("unzip")
|
raise SystemPackageMissingError("unzip")
|
||||||
|
|
||||||
# Run the bun install script.
|
# Run the bun install script.
|
||||||
@ -1279,12 +1291,9 @@ def validate_bun():
|
|||||||
Raises:
|
Raises:
|
||||||
Exit: If custom specified bun does not exist or does not meet requirements.
|
Exit: If custom specified bun does not exist or does not meet requirements.
|
||||||
"""
|
"""
|
||||||
# if a custom bun path is provided, make sure its valid
|
bun_path = path_ops.get_bun_path()
|
||||||
# This is specific to non-FHS OS
|
|
||||||
bun_path = get_config().bun_path
|
if bun_path and bun_path.samefile(constants.Bun.DEFAULT_PATH):
|
||||||
if path_ops.use_system_bun():
|
|
||||||
bun_path = path_ops.which("bun")
|
|
||||||
if bun_path != constants.Bun.DEFAULT_PATH:
|
|
||||||
console.info(f"Using custom Bun path: {bun_path}")
|
console.info(f"Using custom Bun path: {bun_path}")
|
||||||
bun_version = get_bun_version()
|
bun_version = get_bun_version()
|
||||||
if not bun_version:
|
if not bun_version:
|
||||||
|
@ -122,13 +122,13 @@ def test_validate_invalid_bun_path(mocker):
|
|||||||
Args:
|
Args:
|
||||||
mocker: Pytest mocker object.
|
mocker: Pytest mocker object.
|
||||||
"""
|
"""
|
||||||
mock = mocker.Mock()
|
mock_path = mocker.Mock()
|
||||||
mocker.patch.object(mock, "bun_path", return_value="/mock/path")
|
mocker.patch("reflex.utils.path_ops.get_bun_path", return_value=mock_path)
|
||||||
mocker.patch("reflex.utils.prerequisites.get_config", mock)
|
|
||||||
mocker.patch("reflex.utils.prerequisites.get_bun_version", return_value=None)
|
mocker.patch("reflex.utils.prerequisites.get_bun_version", return_value=None)
|
||||||
|
|
||||||
with pytest.raises(typer.Exit):
|
with pytest.raises(typer.Exit):
|
||||||
prerequisites.validate_bun()
|
prerequisites.validate_bun()
|
||||||
|
mock_path.samefile.assert_called_once()
|
||||||
|
|
||||||
|
|
||||||
def test_validate_bun_path_incompatible_version(mocker):
|
def test_validate_bun_path_incompatible_version(mocker):
|
||||||
@ -137,9 +137,8 @@ def test_validate_bun_path_incompatible_version(mocker):
|
|||||||
Args:
|
Args:
|
||||||
mocker: Pytest mocker object.
|
mocker: Pytest mocker object.
|
||||||
"""
|
"""
|
||||||
mock = mocker.Mock()
|
mock_path = mocker.Mock()
|
||||||
mocker.patch.object(mock, "bun_path", return_value="/mock/path")
|
mocker.patch("reflex.utils.path_ops.get_bun_path", return_value=mock_path)
|
||||||
mocker.patch("reflex.utils.prerequisites.get_config", mock)
|
|
||||||
mocker.patch(
|
mocker.patch(
|
||||||
"reflex.utils.prerequisites.get_bun_version",
|
"reflex.utils.prerequisites.get_bun_version",
|
||||||
return_value=version.parse("0.6.5"),
|
return_value=version.parse("0.6.5"),
|
||||||
|
Loading…
Reference in New Issue
Block a user