Skip to content

Commit

Permalink
use pathlib as much as possible (#3967)
Browse files Browse the repository at this point in the history
* use pathlib as much as possible

* fixstuff

* break locally to unbreak in CI 🤷

* add type on env

* debug attempt 1

* debugged

* oops, there is the actual fix

* fix 3.9 compat
  • Loading branch information
Lendemor authored Oct 3, 2024
1 parent f3be9a3 commit 3f51943
Show file tree
Hide file tree
Showing 22 changed files with 202 additions and 260 deletions.
35 changes: 16 additions & 19 deletions benchmarks/benchmark_lighthouse.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
from __future__ import annotations

import json
import os
import sys
from pathlib import Path

from utils import send_data_to_posthog

Expand All @@ -28,7 +28,7 @@ def insert_benchmarking_data(
send_data_to_posthog("lighthouse_benchmark", properties)


def get_lighthouse_scores(directory_path: str) -> dict:
def get_lighthouse_scores(directory_path: str | Path) -> dict:
"""Extracts the Lighthouse scores from the JSON files in the specified directory.
Args:
Expand All @@ -38,24 +38,21 @@ def get_lighthouse_scores(directory_path: str) -> dict:
dict: The Lighthouse scores.
"""
scores = {}

directory_path = Path(directory_path)
try:
for filename in os.listdir(directory_path):
if filename.endswith(".json") and filename != "manifest.json":
file_path = os.path.join(directory_path, filename)
with open(file_path, "r") as file:
data = json.load(file)
# Extract scores and add them to the dictionary with the filename as key
scores[data["finalUrl"].replace("http://localhost:3000/", "/")] = {
"performance_score": data["categories"]["performance"]["score"],
"accessibility_score": data["categories"]["accessibility"][
"score"
],
"best_practices_score": data["categories"]["best-practices"][
"score"
],
"seo_score": data["categories"]["seo"]["score"],
}
for filename in directory_path.iterdir():
if filename.suffix == ".json" and filename.stem != "manifest":
file_path = directory_path / filename
data = json.loads(file_path.read_text())
# Extract scores and add them to the dictionary with the filename as key
scores[data["finalUrl"].replace("http://localhost:3000/", "/")] = {
"performance_score": data["categories"]["performance"]["score"],
"accessibility_score": data["categories"]["accessibility"]["score"],
"best_practices_score": data["categories"]["best-practices"][
"score"
],
"seo_score": data["categories"]["seo"]["score"],
}
except Exception as e:
return {"error": e}

Expand Down
17 changes: 8 additions & 9 deletions benchmarks/benchmark_package_size.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,12 @@

import argparse
import os
from pathlib import Path

from utils import get_directory_size, get_python_version, send_data_to_posthog


def get_package_size(venv_path, os_name):
def get_package_size(venv_path: Path, os_name):
"""Get the size of a specified package.
Args:
Expand All @@ -26,14 +27,12 @@ def get_package_size(venv_path, os_name):

is_windows = "windows" in os_name

full_path = (
["lib", f"python{python_version}", "site-packages"]
package_dir: Path = (
venv_path / "lib" / f"python{python_version}" / "site-packages"
if not is_windows
else ["Lib", "site-packages"]
else venv_path / "Lib" / "site-packages"
)

package_dir = os.path.join(venv_path, *full_path)
if not os.path.exists(package_dir):
if not package_dir.exists():
raise ValueError(
"Error: Virtual environment does not exist or is not activated."
)
Expand Down Expand Up @@ -63,9 +62,9 @@ def insert_benchmarking_data(
path: The path to the dir or file to check size.
"""
if "./dist" in path:
size = get_directory_size(path)
size = get_directory_size(Path(path))
else:
size = get_package_size(path, os_type_version)
size = get_package_size(Path(path), os_type_version)

# Prepare the event data
properties = {
Expand Down
3 changes: 2 additions & 1 deletion benchmarks/benchmark_web_size.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import argparse
import os
from pathlib import Path

from utils import get_directory_size, send_data_to_posthog

Expand All @@ -28,7 +29,7 @@ def insert_benchmarking_data(
pr_id: The id of the PR.
path: The path to the dir or file to check size.
"""
size = get_directory_size(path)
size = get_directory_size(Path(path))

# Prepare the event data
properties = {
Expand Down
15 changes: 8 additions & 7 deletions benchmarks/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,13 @@

import os
import subprocess
from pathlib import Path

import httpx
from httpx import HTTPError


def get_python_version(venv_path, os_name):
def get_python_version(venv_path: Path, os_name):
"""Get the python version of python in a virtual env.
Args:
Expand All @@ -18,21 +19,21 @@ def get_python_version(venv_path, os_name):
The python version.
"""
python_executable = (
os.path.join(venv_path, "bin", "python")
venv_path / "bin" / "python"
if "windows" not in os_name
else os.path.join(venv_path, "Scripts", "python.exe")
else venv_path / "Scripts" / "python.exe"
)
try:
output = subprocess.check_output(
[python_executable, "--version"], stderr=subprocess.STDOUT
[str(python_executable), "--version"], stderr=subprocess.STDOUT
)
python_version = output.decode("utf-8").strip().split()[1]
return ".".join(python_version.split(".")[:-1])
except subprocess.CalledProcessError:
return None


def get_directory_size(directory):
def get_directory_size(directory: Path):
"""Get the size of a directory in bytes.
Args:
Expand All @@ -44,8 +45,8 @@ def get_directory_size(directory):
total_size = 0
for dirpath, _, filenames in os.walk(directory):
for f in filenames:
fp = os.path.join(dirpath, f)
total_size += os.path.getsize(fp)
fp = Path(dirpath) / f
total_size += fp.stat().st_size
return total_size


Expand Down
2 changes: 1 addition & 1 deletion reflex/compiler/compiler.py
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ def _compile_root_stylesheet(stylesheets: list[str]) -> str:
stylesheet_full_path = (
Path.cwd() / constants.Dirs.APP_ASSETS / stylesheet.strip("/")
)
if not os.path.exists(stylesheet_full_path):
if not stylesheet_full_path.exists():
raise FileNotFoundError(
f"The stylesheet file {stylesheet_full_path} does not exist."
)
Expand Down
9 changes: 4 additions & 5 deletions reflex/compiler/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

from __future__ import annotations

import os
from pathlib import Path
from typing import Any, Callable, Dict, Optional, Type, Union
from urllib.parse import urlparse
Expand Down Expand Up @@ -457,16 +456,16 @@ def add_meta(
return page


def write_page(path: str, code: str):
def write_page(path: str | Path, code: str):
"""Write the given code to the given path.
Args:
path: The path to write the code to.
code: The code to write.
"""
path_ops.mkdir(os.path.dirname(path))
with open(path, "w", encoding="utf-8") as f:
f.write(code)
path = Path(path)
path_ops.mkdir(path.parent)
path.write_text(code, encoding="utf-8")


def empty_dir(path: str | Path, keep_files: list[str] | None = None):
Expand Down
5 changes: 3 additions & 2 deletions reflex/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@
import os
import sys
import urllib.parse
from typing import Any, Dict, List, Optional, Set
from pathlib import Path
from typing import Any, Dict, List, Optional, Set, Union

try:
import pydantic.v1 as pydantic
Expand Down Expand Up @@ -188,7 +189,7 @@ class Config:
telemetry_enabled: bool = True

# The bun path
bun_path: str = constants.Bun.DEFAULT_PATH
bun_path: Union[str, Path] = constants.Bun.DEFAULT_PATH

# List of origins that are allowed to connect to the backend API.
cors_allowed_origins: List[str] = ["*"]
Expand Down
26 changes: 14 additions & 12 deletions reflex/constants/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import platform
from enum import Enum
from importlib import metadata
from pathlib import Path
from types import SimpleNamespace

from platformdirs import PlatformDirs
Expand Down Expand Up @@ -66,18 +67,19 @@ class Reflex(SimpleNamespace):
# Get directory value from enviroment variables if it exists.
_dir = os.environ.get("REFLEX_DIR", "")

DIR = _dir or (
# on windows, we use C:/Users/<username>/AppData/Local/reflex.
# on macOS, we use ~/Library/Application Support/reflex.
# on linux, we use ~/.local/share/reflex.
# If user sets REFLEX_DIR envroment variable use that instead.
PlatformDirs(MODULE_NAME, False).user_data_dir
DIR = Path(
_dir
or (
# on windows, we use C:/Users/<username>/AppData/Local/reflex.
# on macOS, we use ~/Library/Application Support/reflex.
# on linux, we use ~/.local/share/reflex.
# If user sets REFLEX_DIR envroment variable use that instead.
PlatformDirs(MODULE_NAME, False).user_data_dir
)
)
# The root directory of the reflex library.

ROOT_DIR = os.path.dirname(
os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
)
ROOT_DIR = Path(__file__).parents[2]

RELEASES_URL = f"https://api.github.com/repos/reflex-dev/templates/releases"

Expand Down Expand Up @@ -125,11 +127,11 @@ class Dirs(SimpleNamespace):
"""Folders used by the template system of Reflex."""

# The template directory used during reflex init.
BASE = os.path.join(Reflex.ROOT_DIR, Reflex.MODULE_NAME, ".templates")
BASE = Reflex.ROOT_DIR / Reflex.MODULE_NAME / ".templates"
# The web subdirectory of the template directory.
WEB_TEMPLATE = os.path.join(BASE, "web")
WEB_TEMPLATE = BASE / "web"
# The jinja template directory.
JINJA_TEMPLATE = os.path.join(BASE, "jinja")
JINJA_TEMPLATE = BASE / "jinja"
# Where the code for the templates is stored.
CODE = "code"

Expand Down
7 changes: 3 additions & 4 deletions reflex/constants/config.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
"""Config constants."""

import os
from pathlib import Path
from types import SimpleNamespace

from reflex.constants.base import Dirs, Reflex
Expand All @@ -17,9 +18,7 @@ class Config(SimpleNamespace):
# The name of the reflex config module.
MODULE = "rxconfig"
# The python config file.
FILE = f"{MODULE}{Ext.PY}"
# The previous config file.
PREVIOUS_FILE = f"pcconfig{Ext.PY}"
FILE = Path(f"{MODULE}{Ext.PY}")


class Expiration(SimpleNamespace):
Expand All @@ -37,7 +36,7 @@ class GitIgnore(SimpleNamespace):
"""Gitignore constants."""

# The gitignore file.
FILE = ".gitignore"
FILE = Path(".gitignore")
# Files to gitignore.
DEFAULTS = {Dirs.WEB, "*.db", "__pycache__/", "*.py[cod]", "assets/external/"}

Expand Down
7 changes: 4 additions & 3 deletions reflex/constants/custom_components.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

from __future__ import annotations

from pathlib import Path
from types import SimpleNamespace


Expand All @@ -11,9 +12,9 @@ class CustomComponents(SimpleNamespace):
# The name of the custom components source directory.
SRC_DIR = "custom_components"
# The name of the custom components pyproject.toml file.
PYPROJECT_TOML = "pyproject.toml"
PYPROJECT_TOML = Path("pyproject.toml")
# The name of the custom components package README file.
PACKAGE_README = "README.md"
PACKAGE_README = Path("README.md")
# The name of the custom components package .gitignore file.
PACKAGE_GITIGNORE = ".gitignore"
# The name of the distribution directory as result of a build.
Expand All @@ -29,6 +30,6 @@ class CustomComponents(SimpleNamespace):
"testpypi": "https://test.pypi.org/legacy/",
}
# The .gitignore file for the custom component project.
FILE = ".gitignore"
FILE = Path(".gitignore")
# Files to gitignore.
DEFAULTS = {"__pycache__/", "*.py[cod]", "*.egg-info/", "dist/"}
Loading

0 comments on commit 3f51943

Please sign in to comment.