enable PTH rule (#4476)

* enable PTH rule

* fix import in test_call_script

* fix units tests

* reorder ruff rules

* Update reflex/utils/build.py

Co-authored-by: Masen Furer <m_github@0x26.net>

* format pyproject.toml

---------

Co-authored-by: Masen Furer <m_github@0x26.net>
This commit is contained in:
Thomas Brandého 2024-12-13 14:06:26 -08:00 committed by GitHub
parent 1444421766
commit 61cb72596e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
19 changed files with 95 additions and 104 deletions

View File

@ -5,6 +5,7 @@ from __future__ import annotations
import argparse import argparse
import json import json
import os import os
from pathlib import Path
from utils import send_data_to_posthog from utils import send_data_to_posthog
@ -18,7 +19,7 @@ def extract_stats_from_json(json_file: str) -> list[dict]:
Returns: Returns:
list[dict]: The stats for each test. list[dict]: The stats for each test.
""" """
with open(json_file, "r") as file: with Path(json_file).open() as file:
json_data = json.load(file) json_data = json.load(file)
# Load the JSON data if it is a string, otherwise assume it's already a dictionary # Load the JSON data if it is a string, otherwise assume it's already a dictionary

View File

@ -5,6 +5,7 @@ from __future__ import annotations
import argparse import argparse
import json import json
import os import os
from pathlib import Path
from utils import send_data_to_posthog from utils import send_data_to_posthog
@ -18,7 +19,7 @@ def extract_stats_from_json(json_file: str) -> dict:
Returns: Returns:
dict: The stats for each test. dict: The stats for each test.
""" """
with open(json_file, "r") as file: with Path(json_file).open() as file:
json_data = json.load(file) json_data = json.load(file)
# Load the JSON data if it is a string, otherwise assume it's already a dictionary # Load the JSON data if it is a string, otherwise assume it's already a dictionary

View File

@ -4,26 +4,19 @@ version = "0.6.7dev1"
description = "Web apps in pure Python." description = "Web apps in pure Python."
license = "Apache-2.0" license = "Apache-2.0"
authors = [ authors = [
"Nikhil Rao <nikhil@reflex.dev>", "Nikhil Rao <nikhil@reflex.dev>",
"Alek Petuskey <alek@reflex.dev>", "Alek Petuskey <alek@reflex.dev>",
"Masen Furer <masen@reflex.dev>", "Masen Furer <masen@reflex.dev>",
"Elijah Ahianyo <elijah@reflex.dev>", "Elijah Ahianyo <elijah@reflex.dev>",
"Thomas Brandého <thomas@reflex.dev>", "Thomas Brandého <thomas@reflex.dev>",
] ]
readme = "README.md" readme = "README.md"
homepage = "https://reflex.dev" homepage = "https://reflex.dev"
repository = "https://github.com/reflex-dev/reflex" repository = "https://github.com/reflex-dev/reflex"
documentation = "https://reflex.dev/docs/getting-started/introduction" documentation = "https://reflex.dev/docs/getting-started/introduction"
keywords = [ keywords = ["web", "framework"]
"web", classifiers = ["Development Status :: 4 - Beta"]
"framework", packages = [{ include = "reflex" }]
]
classifiers = [
"Development Status :: 4 - Beta",
]
packages = [
{include = "reflex"}
]
[tool.poetry.dependencies] [tool.poetry.dependencies]
python = "^3.9" python = "^3.9"
@ -42,11 +35,11 @@ uvicorn = ">=0.20.0"
starlette-admin = ">=0.11.0,<1.0" starlette-admin = ">=0.11.0,<1.0"
alembic = ">=1.11.1,<2.0" alembic = ">=1.11.1,<2.0"
platformdirs = ">=3.10.0,<5.0" platformdirs = ">=3.10.0,<5.0"
distro = {version = ">=1.8.0,<2.0", platform = "linux"} distro = { version = ">=1.8.0,<2.0", platform = "linux" }
python-engineio = "!=4.6.0" python-engineio = "!=4.6.0"
wrapt = [ wrapt = [
{version = ">=1.14.0,<2.0", python = ">=3.11"}, { version = ">=1.14.0,<2.0", python = ">=3.11" },
{version = ">=1.11.0,<2.0", python = "<3.11"}, { version = ">=1.11.0,<2.0", python = "<3.11" },
] ]
packaging = ">=23.1,<25.0" packaging = ">=23.1,<25.0"
reflex-hosting-cli = ">=0.1.29,<2.0" reflex-hosting-cli = ">=0.1.29,<2.0"
@ -93,7 +86,7 @@ build-backend = "poetry.core.masonry.api"
[tool.ruff] [tool.ruff]
target-version = "py39" target-version = "py39"
lint.isort.split-on-trailing-comma = false lint.isort.split-on-trailing-comma = false
lint.select = ["B", "C4", "D", "E", "ERA", "F", "FURB", "I", "RUF", "SIM", "W"] lint.select = ["B", "C4", "D", "E", "ERA", "F", "FURB", "I", "PTH", "RUF", "SIM", "W"]
lint.ignore = ["B008", "D205", "E501", "F403", "SIM115", "RUF006", "RUF012"] lint.ignore = ["B008", "D205", "E501", "F403", "SIM115", "RUF006", "RUF012"]
lint.pydocstyle.convention = "google" lint.pydocstyle.convention = "google"

View File

@ -873,7 +873,7 @@ def get_config(reload: bool = False) -> Config:
with _config_lock: with _config_lock:
sys_path = sys.path.copy() sys_path = sys.path.copy()
sys.path.clear() sys.path.clear()
sys.path.append(os.getcwd()) sys.path.append(str(Path.cwd()))
try: try:
# Try to import the module with only the current directory in the path. # Try to import the module with only the current directory in the path.
return _get_config() return _get_config()

View File

@ -10,7 +10,7 @@ class CustomComponents(SimpleNamespace):
"""Constants for the custom components.""" """Constants for the custom components."""
# The name of the custom components source directory. # The name of the custom components source directory.
SRC_DIR = "custom_components" SRC_DIR = Path("custom_components")
# The name of the custom components pyproject.toml file. # The name of the custom components pyproject.toml file.
PYPROJECT_TOML = Path("pyproject.toml") PYPROJECT_TOML = Path("pyproject.toml")
# The name of the custom components package README file. # The name of the custom components package README file.

View File

@ -150,27 +150,27 @@ def _populate_demo_app(name_variants: NameVariants):
from reflex.compiler import templates from reflex.compiler import templates
from reflex.reflex import _init from reflex.reflex import _init
demo_app_dir = name_variants.demo_app_dir demo_app_dir = Path(name_variants.demo_app_dir)
demo_app_name = name_variants.demo_app_name demo_app_name = name_variants.demo_app_name
console.info(f"Creating app for testing: {demo_app_dir}") console.info(f"Creating app for testing: {demo_app_dir!s}")
os.makedirs(demo_app_dir) demo_app_dir.mkdir(exist_ok=True)
with set_directory(demo_app_dir): with set_directory(demo_app_dir):
# We start with the blank template as basis. # We start with the blank template as basis.
_init(name=demo_app_name, template=constants.Templates.DEFAULT) _init(name=demo_app_name, template=constants.Templates.DEFAULT)
# Then overwrite the app source file with the one we want for testing custom components. # Then overwrite the app source file with the one we want for testing custom components.
# This source file is rendered using jinja template file. # This source file is rendered using jinja template file.
with open(f"{demo_app_name}/{demo_app_name}.py", "w") as f: demo_file = Path(f"{demo_app_name}/{demo_app_name}.py")
f.write( demo_file.write_text(
templates.CUSTOM_COMPONENTS_DEMO_APP.render( templates.CUSTOM_COMPONENTS_DEMO_APP.render(
custom_component_module_dir=name_variants.custom_component_module_dir, custom_component_module_dir=name_variants.custom_component_module_dir,
module_name=name_variants.module_name, module_name=name_variants.module_name,
)
) )
)
# Append the custom component package to the requirements.txt file. # Append the custom component package to the requirements.txt file.
with open(f"{constants.RequirementsTxt.FILE}", "a") as f: with Path(f"{constants.RequirementsTxt.FILE}").open(mode="a") as f:
f.write(f"{name_variants.package_name}\n") f.write(f"{name_variants.package_name}\n")
@ -296,13 +296,14 @@ def _populate_custom_component_project(name_variants: NameVariants):
) )
console.info( console.info(
f"Initializing the component directory: {CustomComponents.SRC_DIR}/{name_variants.custom_component_module_dir}" f"Initializing the component directory: {CustomComponents.SRC_DIR / name_variants.custom_component_module_dir}"
) )
os.makedirs(CustomComponents.SRC_DIR) CustomComponents.SRC_DIR.mkdir(exist_ok=True)
with set_directory(CustomComponents.SRC_DIR): with set_directory(CustomComponents.SRC_DIR):
os.makedirs(name_variants.custom_component_module_dir) module_dir = Path(name_variants.custom_component_module_dir)
module_dir.mkdir(exist_ok=True, parents=True)
_write_source_and_init_py( _write_source_and_init_py(
custom_component_src_dir=name_variants.custom_component_module_dir, custom_component_src_dir=module_dir,
component_class_name=name_variants.component_class_name, component_class_name=name_variants.component_class_name,
module_name=name_variants.module_name, module_name=name_variants.module_name,
) )
@ -814,7 +815,7 @@ def _validate_project_info():
) )
pyproject_toml["project"] = project pyproject_toml["project"] = project
try: try:
with open(CustomComponents.PYPROJECT_TOML, "w") as f: with CustomComponents.PYPROJECT_TOML.open("w") as f:
tomlkit.dump(pyproject_toml, f) tomlkit.dump(pyproject_toml, f)
except (OSError, TOMLKitError) as ex: except (OSError, TOMLKitError) as ex:
console.error(f"Unable to write to pyproject.toml due to {ex}") console.error(f"Unable to write to pyproject.toml due to {ex}")
@ -922,16 +923,15 @@ def _validate_url_with_protocol_prefix(url: str | None) -> bool:
def _get_file_from_prompt_in_loop() -> Tuple[bytes, str] | None: def _get_file_from_prompt_in_loop() -> Tuple[bytes, str] | None:
image_file = file_extension = None image_file = file_extension = None
while image_file is None: while image_file is None:
image_filepath = console.ask( image_filepath = Path(
"Upload a preview image of your demo app (enter to skip)" console.ask("Upload a preview image of your demo app (enter to skip)")
) )
if not image_filepath: if not image_filepath:
break break
file_extension = image_filepath.split(".")[-1] file_extension = image_filepath.suffix
try: try:
with open(image_filepath, "rb") as f: image_file = image_filepath.read_bytes()
image_file = f.read() return image_file, file_extension
return image_file, file_extension
except OSError as ose: except OSError as ose:
console.error(f"Unable to read the {file_extension} file due to {ose}") console.error(f"Unable to read the {file_extension} file due to {ose}")
raise typer.Exit(code=1) from ose raise typer.Exit(code=1) from ose

View File

@ -3,7 +3,6 @@
from __future__ import annotations from __future__ import annotations
import atexit import atexit
import os
from pathlib import Path from pathlib import Path
from typing import List, Optional from typing import List, Optional
@ -298,7 +297,7 @@ def export(
True, "--frontend-only", help="Export only frontend.", show_default=False True, "--frontend-only", help="Export only frontend.", show_default=False
), ),
zip_dest_dir: str = typer.Option( zip_dest_dir: str = typer.Option(
os.getcwd(), str(Path.cwd()),
help="The directory to export the zip files to.", help="The directory to export the zip files to.",
show_default=False, show_default=False,
), ),

View File

@ -8,7 +8,6 @@ import dataclasses
import functools import functools
import inspect import inspect
import os import os
import pathlib
import platform import platform
import re import re
import signal import signal
@ -20,6 +19,7 @@ import threading
import time import time
import types import types
from http.server import SimpleHTTPRequestHandler from http.server import SimpleHTTPRequestHandler
from pathlib import Path
from typing import ( from typing import (
TYPE_CHECKING, TYPE_CHECKING,
Any, Any,
@ -100,7 +100,7 @@ class chdir(contextlib.AbstractContextManager):
def __enter__(self): def __enter__(self):
"""Save current directory and perform chdir.""" """Save current directory and perform chdir."""
self._old_cwd.append(os.getcwd()) self._old_cwd.append(Path.cwd())
os.chdir(self.path) os.chdir(self.path)
def __exit__(self, *excinfo): def __exit__(self, *excinfo):
@ -120,8 +120,8 @@ class AppHarness:
app_source: Optional[ app_source: Optional[
Callable[[], None] | types.ModuleType | str | functools.partial[Any] Callable[[], None] | types.ModuleType | str | functools.partial[Any]
] ]
app_path: pathlib.Path app_path: Path
app_module_path: pathlib.Path app_module_path: Path
app_module: Optional[types.ModuleType] = None app_module: Optional[types.ModuleType] = None
app_instance: Optional[reflex.App] = None app_instance: Optional[reflex.App] = None
frontend_process: Optional[subprocess.Popen] = None frontend_process: Optional[subprocess.Popen] = None
@ -136,7 +136,7 @@ class AppHarness:
@classmethod @classmethod
def create( def create(
cls, cls,
root: pathlib.Path, root: Path,
app_source: Optional[ app_source: Optional[
Callable[[], None] | types.ModuleType | str | functools.partial[Any] Callable[[], None] | types.ModuleType | str | functools.partial[Any]
] = None, ] = None,
@ -814,7 +814,7 @@ class AppHarness:
class SimpleHTTPRequestHandlerCustomErrors(SimpleHTTPRequestHandler): class SimpleHTTPRequestHandlerCustomErrors(SimpleHTTPRequestHandler):
"""SimpleHTTPRequestHandler with custom error page handling.""" """SimpleHTTPRequestHandler with custom error page handling."""
def __init__(self, *args, error_page_map: dict[int, pathlib.Path], **kwargs): def __init__(self, *args, error_page_map: dict[int, Path], **kwargs):
"""Initialize the handler. """Initialize the handler.
Args: Args:
@ -857,8 +857,8 @@ class Subdir404TCPServer(socketserver.TCPServer):
def __init__( def __init__(
self, self,
*args, *args,
root: pathlib.Path, root: Path,
error_page_map: dict[int, pathlib.Path] | None, error_page_map: dict[int, Path] | None,
**kwargs, **kwargs,
): ):
"""Initialize the server. """Initialize the server.

View File

@ -150,7 +150,7 @@ def zip_app(
_zip( _zip(
component_name=constants.ComponentName.BACKEND, component_name=constants.ComponentName.BACKEND,
target=zip_dest_dir / constants.ComponentName.BACKEND.zip(), target=zip_dest_dir / constants.ComponentName.BACKEND.zip(),
root_dir=Path("."), root_dir=Path.cwd(),
dirs_to_exclude={"__pycache__"}, dirs_to_exclude={"__pycache__"},
files_to_exclude=files_to_exclude, files_to_exclude=files_to_exclude,
top_level_dirs_to_exclude={"assets"}, top_level_dirs_to_exclude={"assets"},

View File

@ -24,7 +24,7 @@ from reflex.utils.prerequisites import get_web_dir
frontend_process = None frontend_process = None
def detect_package_change(json_file_path: str) -> str: def detect_package_change(json_file_path: Path) -> str:
"""Calculates the SHA-256 hash of a JSON file and returns it as a hexadecimal string. """Calculates the SHA-256 hash of a JSON file and returns it as a hexadecimal string.
Args: Args:
@ -37,7 +37,7 @@ def detect_package_change(json_file_path: str) -> str:
>>> detect_package_change("package.json") >>> detect_package_change("package.json")
'a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0u1v2w3x4y5z6a7b8c9d0e1f2' 'a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0u1v2w3x4y5z6a7b8c9d0e1f2'
""" """
with open(json_file_path, "r") as file: with json_file_path.open("r") as file:
json_data = json.load(file) json_data = json.load(file)
# Calculate the hash # Calculate the hash
@ -81,7 +81,7 @@ def run_process_and_launch_url(run_command: list[str], backend_present=True):
from reflex.utils import processes from reflex.utils import processes
json_file_path = get_web_dir() / constants.PackageJson.PATH json_file_path = get_web_dir() / constants.PackageJson.PATH
last_hash = detect_package_change(str(json_file_path)) last_hash = detect_package_change(json_file_path)
process = None process = None
first_run = True first_run = True
@ -124,7 +124,7 @@ def run_process_and_launch_url(run_command: list[str], backend_present=True):
"`REFLEX_USE_NPM=1 reflex init`\n" "`REFLEX_USE_NPM=1 reflex init`\n"
"`REFLEX_USE_NPM=1 reflex run`" "`REFLEX_USE_NPM=1 reflex run`"
) )
new_hash = detect_package_change(str(json_file_path)) new_hash = detect_package_change(json_file_path)
if new_hash != last_hash: if new_hash != last_hash:
last_hash = new_hash last_hash = new_hash
kill(process.pid) kill(process.pid)

View File

@ -1,6 +1,5 @@
"""Export utilities.""" """Export utilities."""
import os
from pathlib import Path from pathlib import Path
from typing import Optional from typing import Optional
@ -15,7 +14,7 @@ def export(
zipping: bool = True, zipping: bool = True,
frontend: bool = True, frontend: bool = True,
backend: bool = True, backend: bool = True,
zip_dest_dir: str = os.getcwd(), zip_dest_dir: str = str(Path.cwd()),
upload_db_file: bool = False, upload_db_file: bool = False,
api_url: Optional[str] = None, api_url: Optional[str] = None,
deploy_url: Optional[str] = None, deploy_url: Optional[str] = None,

View File

@ -205,14 +205,14 @@ def update_json_file(file_path: str | Path, update_dict: dict[str, int | str]):
# Read the existing json object from the file. # Read the existing json object from the file.
json_object = {} json_object = {}
if fp.stat().st_size: if fp.stat().st_size:
with open(fp) as f: with fp.open() as f:
json_object = json.load(f) json_object = json.load(f)
# Update the json object with the new data. # Update the json object with the new data.
json_object.update(update_dict) json_object.update(update_dict)
# Write the updated json object to the file # Write the updated json object to the file
with open(fp, "w") as f: with fp.open("w") as f:
json.dump(json_object, f, ensure_ascii=False) json.dump(json_object, f, ensure_ascii=False)

View File

@ -290,7 +290,7 @@ def get_app(reload: bool = False) -> ModuleType:
"If this error occurs in a reflex test case, ensure that `get_app` is mocked." "If this error occurs in a reflex test case, ensure that `get_app` is mocked."
) )
module = config.module module = config.module
sys.path.insert(0, os.getcwd()) sys.path.insert(0, str(Path.cwd()))
app = __import__(module, fromlist=(constants.CompileVars.APP,)) app = __import__(module, fromlist=(constants.CompileVars.APP,))
if reload: if reload:
@ -438,9 +438,11 @@ def create_config(app_name: str):
from reflex.compiler import templates from reflex.compiler import templates
config_name = f"{re.sub(r'[^a-zA-Z]', '', app_name).capitalize()}Config" config_name = f"{re.sub(r'[^a-zA-Z]', '', app_name).capitalize()}Config"
with open(constants.Config.FILE, "w") as f:
console.debug(f"Creating {constants.Config.FILE}") console.debug(f"Creating {constants.Config.FILE}")
f.write(templates.RXCONFIG.render(app_name=app_name, config_name=config_name)) constants.Config.FILE.write_text(
templates.RXCONFIG.render(app_name=app_name, config_name=config_name)
)
def initialize_gitignore( def initialize_gitignore(
@ -494,14 +496,14 @@ def initialize_requirements_txt():
console.debug(f"Detected encoding for {fp} as {encoding}.") console.debug(f"Detected encoding for {fp} as {encoding}.")
try: try:
other_requirements_exist = False other_requirements_exist = False
with open(fp, "r", encoding=encoding) as f: with fp.open("r", encoding=encoding) as f:
for req in f: for req in f:
# Check if we have a package name that is reflex # Check if we have a package name that is reflex
if re.match(r"^reflex[^a-zA-Z0-9]", req): if re.match(r"^reflex[^a-zA-Z0-9]", req):
console.debug(f"{fp} already has reflex as dependency.") console.debug(f"{fp} already has reflex as dependency.")
return return
other_requirements_exist = True other_requirements_exist = True
with open(fp, "a", encoding=encoding) as f: with fp.open("a", encoding=encoding) as f:
preceding_newline = "\n" if other_requirements_exist else "" preceding_newline = "\n" if other_requirements_exist else ""
f.write( f.write(
f"{preceding_newline}{constants.RequirementsTxt.DEFAULTS_STUB}{constants.Reflex.VERSION}\n" f"{preceding_newline}{constants.RequirementsTxt.DEFAULTS_STUB}{constants.Reflex.VERSION}\n"
@ -732,13 +734,13 @@ def download_and_run(url: str, *args, show_status: bool = False, **env):
response.raise_for_status() response.raise_for_status()
# Save the script to a temporary file. # Save the script to a temporary file.
script = tempfile.NamedTemporaryFile() script = Path(tempfile.NamedTemporaryFile().name)
with open(script.name, "w") as f:
f.write(response.text) script.write_text(response.text)
# Run the script. # Run the script.
env = {**os.environ, **env} env = {**os.environ, **env}
process = processes.new_process(["bash", f.name, *args], env=env) process = processes.new_process(["bash", str(script), *args], env=env)
show = processes.show_status if show_status else processes.show_logs show = processes.show_status if show_status else processes.show_logs
show(f"Installing {url}", process) show(f"Installing {url}", process)
@ -752,14 +754,14 @@ def download_and_extract_fnm_zip():
# Download the zip file # Download the zip file
url = constants.Fnm.INSTALL_URL url = constants.Fnm.INSTALL_URL
console.debug(f"Downloading {url}") console.debug(f"Downloading {url}")
fnm_zip_file = constants.Fnm.DIR / f"{constants.Fnm.FILENAME}.zip" fnm_zip_file: Path = constants.Fnm.DIR / f"{constants.Fnm.FILENAME}.zip"
# Function to download and extract the FNM zip release. # Function to download and extract the FNM zip release.
try: try:
# Download the FNM zip release. # Download the FNM zip release.
# TODO: show progress to improve UX # TODO: show progress to improve UX
response = net.get(url, follow_redirects=True) response = net.get(url, follow_redirects=True)
response.raise_for_status() response.raise_for_status()
with open(fnm_zip_file, "wb") as output_file: with fnm_zip_file.open("wb") as output_file:
for chunk in response.iter_bytes(): for chunk in response.iter_bytes():
output_file.write(chunk) output_file.write(chunk)
@ -807,7 +809,7 @@ def install_node():
) )
else: # All other platforms (Linux, MacOS). else: # All other platforms (Linux, MacOS).
# Add execute permissions to fnm executable. # Add execute permissions to fnm executable.
os.chmod(constants.Fnm.EXE, stat.S_IXUSR) constants.Fnm.EXE.chmod(stat.S_IXUSR)
# Install node. # Install node.
# Specify arm64 arch explicitly for M1s and M2s. # Specify arm64 arch explicitly for M1s and M2s.
architecture_arg = ( architecture_arg = (
@ -1326,7 +1328,7 @@ def create_config_init_app_from_remote_template(app_name: str, template_url: str
raise typer.Exit(1) from ose raise typer.Exit(1) from ose
# Use httpx GET with redirects to download the zip file. # Use httpx GET with redirects to download the zip file.
zip_file_path = Path(temp_dir) / "template.zip" zip_file_path: Path = Path(temp_dir) / "template.zip"
try: try:
# Note: following redirects can be risky. We only allow this for reflex built templates at the moment. # Note: following redirects can be risky. We only allow this for reflex built templates at the moment.
response = net.get(template_url, follow_redirects=True) response = net.get(template_url, follow_redirects=True)
@ -1336,9 +1338,8 @@ def create_config_init_app_from_remote_template(app_name: str, template_url: str
console.error(f"Failed to download the template: {he}") console.error(f"Failed to download the template: {he}")
raise typer.Exit(1) from he raise typer.Exit(1) from he
try: try:
with open(zip_file_path, "wb") as f: zip_file_path.write_bytes(response.content)
f.write(response.content) console.debug(f"Downloaded the zip to {zip_file_path}")
console.debug(f"Downloaded the zip to {zip_file_path}")
except OSError as ose: except OSError as ose:
console.error(f"Unable to write the downloaded zip to disk {ose}") console.error(f"Unable to write the downloaded zip to disk {ose}")
raise typer.Exit(1) from ose raise typer.Exit(1) from ose

View File

@ -210,7 +210,7 @@ class LiteralDatetimeVar(LiteralVar, DateTimeVar):
Returns: Returns:
LiteralDatetimeVar: The new instance of the class. LiteralDatetimeVar: The new instance of the class.
""" """
js_expr = f'"{str(value)}"' js_expr = f'"{value!s}"'
return cls( return cls(
_js_expr=js_expr, _js_expr=js_expr,
_var_type=type(value), _var_type=type(value),

View File

@ -15,6 +15,7 @@ from .utils import SessionStorage
def CallScript(): def CallScript():
"""A test app for browser javascript integration.""" """A test app for browser javascript integration."""
from pathlib import Path
from typing import Dict, List, Optional, Union from typing import Dict, List, Optional, Union
import reflex as rx import reflex as rx
@ -186,8 +187,7 @@ def CallScript():
self.reset() self.reset()
app = rx.App(state=rx.State) app = rx.App(state=rx.State)
with open("assets/external.js", "w") as f: Path("assets/external.js").write_text(external_scripts)
f.write(external_scripts)
@app.add_page @app.add_page
def index(): def index():

View File

@ -61,14 +61,13 @@ class FileUploadState(State):
""" """
for file in files: for file in files:
upload_data = await file.read() upload_data = await file.read()
outfile = f"{self._tmp_path}/{file.filename}" assert file.filename is not None
outfile = self._tmp_path / file.filename
# Save the file. # Save the file.
with open(outfile, "wb") as file_object: outfile.write_bytes(upload_data)
file_object.write(upload_data)
# Update the img var. # Update the img var.
assert file.filename is not None
self.img_list.append(file.filename) self.img_list.append(file.filename)
@rx.event(background=True) @rx.event(background=True)
@ -109,14 +108,13 @@ class ChildFileUploadState(FileStateBase1):
""" """
for file in files: for file in files:
upload_data = await file.read() upload_data = await file.read()
outfile = f"{self._tmp_path}/{file.filename}" assert file.filename is not None
outfile = self._tmp_path / file.filename
# Save the file. # Save the file.
with open(outfile, "wb") as file_object: outfile.write_bytes(upload_data)
file_object.write(upload_data)
# Update the img var. # Update the img var.
assert file.filename is not None
self.img_list.append(file.filename) self.img_list.append(file.filename)
@rx.event(background=True) @rx.event(background=True)
@ -157,14 +155,13 @@ class GrandChildFileUploadState(FileStateBase2):
""" """
for file in files: for file in files:
upload_data = await file.read() upload_data = await file.read()
outfile = f"{self._tmp_path}/{file.filename}" assert file.filename is not None
outfile = self._tmp_path / file.filename
# Save the file. # Save the file.
with open(outfile, "wb") as file_object: outfile.write_bytes(upload_data)
file_object.write(upload_data)
# Update the img var. # Update the img var.
assert file.filename is not None
self.img_list.append(file.filename) self.img_list.append(file.filename)
@rx.event(background=True) @rx.event(background=True)

View File

@ -105,8 +105,8 @@ def test_initialize_requirements_txt_no_op(mocker):
return_value=Mock(best=lambda: Mock(encoding="utf-8")), return_value=Mock(best=lambda: Mock(encoding="utf-8")),
) )
mock_fp_touch = mocker.patch("pathlib.Path.touch") mock_fp_touch = mocker.patch("pathlib.Path.touch")
open_mock = mock_open(read_data="reflex==0.2.9") open_mock = mock_open(read_data="reflex==0.6.7")
mocker.patch("builtins.open", open_mock) mocker.patch("pathlib.Path.open", open_mock)
initialize_requirements_txt() initialize_requirements_txt()
assert open_mock.call_count == 1 assert open_mock.call_count == 1
assert open_mock.call_args.kwargs["encoding"] == "utf-8" assert open_mock.call_args.kwargs["encoding"] == "utf-8"
@ -122,7 +122,7 @@ def test_initialize_requirements_txt_missing_reflex(mocker):
return_value=Mock(best=lambda: Mock(encoding="utf-8")), return_value=Mock(best=lambda: Mock(encoding="utf-8")),
) )
open_mock = mock_open(read_data="random-package=1.2.3") open_mock = mock_open(read_data="random-package=1.2.3")
mocker.patch("builtins.open", open_mock) mocker.patch("pathlib.Path.open", open_mock)
initialize_requirements_txt() initialize_requirements_txt()
# Currently open for read, then open for append # Currently open for read, then open for append
assert open_mock.call_count == 2 assert open_mock.call_count == 2
@ -138,7 +138,7 @@ def test_initialize_requirements_txt_not_exist(mocker):
# File does not exist, create file with reflex # File does not exist, create file with reflex
mocker.patch("pathlib.Path.exists", return_value=False) mocker.patch("pathlib.Path.exists", return_value=False)
open_mock = mock_open() open_mock = mock_open()
mocker.patch("builtins.open", open_mock) mocker.patch("pathlib.Path.open", open_mock)
initialize_requirements_txt() initialize_requirements_txt()
assert open_mock.call_count == 2 assert open_mock.call_count == 2
# By default, use utf-8 encoding # By default, use utf-8 encoding
@ -170,7 +170,7 @@ def test_requirements_txt_other_encoding(mocker):
) )
initialize_requirements_txt() initialize_requirements_txt()
open_mock = mock_open(read_data="random-package=1.2.3") open_mock = mock_open(read_data="random-package=1.2.3")
mocker.patch("builtins.open", open_mock) mocker.patch("pathlib.Path.open", open_mock)
initialize_requirements_txt() initialize_requirements_txt()
# Currently open for read, then open for append # Currently open for read, then open for append
assert open_mock.call_count == 2 assert open_mock.call_count == 2

View File

@ -225,7 +225,7 @@ def test_serialize(value: Any, expected: str):
(datetime.date(2021, 1, 1), '"2021-01-01"', True), (datetime.date(2021, 1, 1), '"2021-01-01"', True),
(Color(color="slate", shade=1), '"var(--slate-1)"', True), (Color(color="slate", shade=1), '"var(--slate-1)"', True),
(BaseSubclass, '"BaseSubclass"', True), (BaseSubclass, '"BaseSubclass"', True),
(Path("."), '"."', True), (Path(), '"."', True),
], ],
) )
def test_serialize_var_to_str(value: Any, expected: str, exp_var_is_string: bool): def test_serialize_var_to_str(value: Any, expected: str, exp_var_is_string: bool):

View File

@ -270,7 +270,7 @@ def test_unsupported_literals(cls: type):
("appname2.io", "AppnameioConfig"), ("appname2.io", "AppnameioConfig"),
], ],
) )
def test_create_config(app_name, expected_config_name, mocker): def test_create_config(app_name: str, expected_config_name: str, mocker):
"""Test templates.RXCONFIG is formatted with correct app name and config class name. """Test templates.RXCONFIG is formatted with correct app name and config class name.
Args: Args:
@ -278,7 +278,7 @@ def test_create_config(app_name, expected_config_name, mocker):
expected_config_name: Expected config name. expected_config_name: Expected config name.
mocker: Mocker object. mocker: Mocker object.
""" """
mocker.patch("builtins.open") mocker.patch("pathlib.Path.write_text")
tmpl_mock = mocker.patch("reflex.compiler.templates.RXCONFIG") tmpl_mock = mocker.patch("reflex.compiler.templates.RXCONFIG")
prerequisites.create_config(app_name) prerequisites.create_config(app_name)
tmpl_mock.render.assert_called_with( tmpl_mock.render.assert_called_with(
@ -464,7 +464,7 @@ def test_node_install_unix(tmp_path, mocker, machine, system):
mocker.patch("httpx.stream", return_value=Resp()) mocker.patch("httpx.stream", return_value=Resp())
download = mocker.patch("reflex.utils.prerequisites.download_and_extract_fnm_zip") download = mocker.patch("reflex.utils.prerequisites.download_and_extract_fnm_zip")
process = mocker.patch("reflex.utils.processes.new_process") process = mocker.patch("reflex.utils.processes.new_process")
chmod = mocker.patch("reflex.utils.prerequisites.os.chmod") chmod = mocker.patch("pathlib.Path.chmod")
mocker.patch("reflex.utils.processes.stream_logs") mocker.patch("reflex.utils.processes.stream_logs")
prerequisites.install_node() prerequisites.install_node()