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

enable PERF rules #4469

Merged
merged 7 commits into from
Dec 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -85,14 +85,15 @@ build-backend = "poetry.core.masonry.api"

[tool.ruff]
target-version = "py39"
output-format = "concise"
lint.isort.split-on-trailing-comma = false
lint.select = ["B", "C4", "D", "E", "ERA", "F", "FURB", "I", "PTH", "RUF", "SIM", "W"]
lint.select = ["B", "C4", "D", "E", "ERA", "F", "FURB", "I", "PERF", "PTH", "RUF", "SIM", "W"]
lint.ignore = ["B008", "D205", "E501", "F403", "SIM115", "RUF006", "RUF012"]
lint.pydocstyle.convention = "google"

[tool.ruff.lint.per-file-ignores]
"__init__.py" = ["F401"]
"tests/*.py" = ["D100", "D103", "D104", "B018"]
"tests/*.py" = ["D100", "D103", "D104", "B018", "PERF"]
"reflex/.templates/*.py" = ["D100", "D103", "D104"]
"*.pyi" = ["D301", "D415", "D417", "D418", "E742"]
"*/blank.py" = ["I001"]
Expand Down
15 changes: 8 additions & 7 deletions reflex/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,15 +30,16 @@ def validate_field_name(bases: List[Type["BaseModel"]], field_name: str) -> None

# can't use reflex.config.environment here cause of circular import
reload = os.getenv("__RELOAD_CONFIG", "").lower() == "true"
for base in bases:
try:
base = None
try:
for base in bases:
if not reload and getattr(base, field_name, None):
pass
except TypeError as te:
raise VarNameError(
f'State var "{field_name}" in {base} has been shadowed by a substate var; '
f'use a different field name instead".'
) from te
except TypeError as te:
raise VarNameError(
f'State var "{field_name}" in {base} has been shadowed by a substate var; '
f'use a different field name instead".'
) from te


# monkeypatch pydantic validate_field_name method to skip validating
Expand Down
3 changes: 1 addition & 2 deletions reflex/compiler/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -123,8 +123,7 @@ def compile_imports(import_dict: ParsedImportDict) -> list[dict]:
raise ValueError("No default field allowed for empty library.")
if rest is None or len(rest) == 0:
raise ValueError("No fields to import.")
for module in sorted(rest):
import_dicts.append(get_import_dict(module))
import_dicts.extend(get_import_dict(module) for module in sorted(rest))
continue

# remove the version before rendering the package imports
Expand Down
8 changes: 4 additions & 4 deletions reflex/components/component.py
Original file line number Diff line number Diff line change
Expand Up @@ -1403,8 +1403,9 @@ def _get_imports(self) -> ParsedImportDict:
if not isinstance(list_of_import_dict, list):
list_of_import_dict = [list_of_import_dict]

for import_dict in list_of_import_dict:
added_import_dicts.append(parse_imports(import_dict))
added_import_dicts.extend(
[parse_imports(import_dict) for import_dict in list_of_import_dict]
)

return imports.merge_imports(
*self._get_props_imports(),
Expand Down Expand Up @@ -1586,8 +1587,7 @@ def _get_all_hooks(self) -> dict[str, None]:
if hooks is not None:
code[hooks] = None

for hook, var_data in self._get_added_hooks().items():
code[hook] = var_data
code.update(self._get_added_hooks())

# Add the hook code for the children.
for child in self.children:
Expand Down
2 changes: 1 addition & 1 deletion reflex/components/el/elements/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@


EXCLUDE = ["del_", "Del", "image"]
for _, v in _MAPPING.items():
for v in _MAPPING.values():
v.extend([mod.capitalize() for mod in v if mod not in EXCLUDE])

_SUBMOD_ATTRS: dict[str, list[str]] = _MAPPING
Expand Down
2 changes: 1 addition & 1 deletion reflex/components/el/elements/__init__.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -339,5 +339,5 @@ _MAPPING = {
],
}
EXCLUDE = ["del_", "Del", "image"]
for _, v in _MAPPING.items():
for v in _MAPPING.values():
v.extend([mod.capitalize() for mod in v if mod not in EXCLUDE])
15 changes: 8 additions & 7 deletions reflex/event.py
Original file line number Diff line number Diff line change
Expand Up @@ -350,13 +350,14 @@ def add_args(self, *args: Var) -> EventSpec:

# Construct the payload.
values = []
for arg in args:
try:
values.append(LiteralVar.create(arg))
except TypeError as e:
raise EventHandlerTypeError(
f"Arguments to event handlers must be Vars or JSON-serializable. Got {arg} of type {type(arg)}."
) from e
arg = None
try:
for arg in args:
values.append(LiteralVar.create(value=arg)) # noqa: PERF401
except TypeError as e:
raise EventHandlerTypeError(
f"Arguments to event handlers must be Vars or JSON-serializable. Got {arg} of type {type(arg)}."
) from e
new_payload = tuple(zip(fn_args, values))
return self.with_args(self.args + new_payload)

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

import re
from collections import defaultdict
from contextlib import suppress
from typing import Any, ClassVar, Optional, Type, Union

import alembic.autogenerate
Expand Down Expand Up @@ -290,11 +291,10 @@ def dict(self, **kwargs):
relationships = {}
# SQLModel relationships do not appear in __fields__, but should be included if present.
for name in self.__sqlmodel_relationships__:
try:
with suppress(
sqlalchemy.orm.exc.DetachedInstanceError # This happens when the relationship was never loaded and the session is closed.
):
relationships[name] = self._dict_recursive(getattr(self, name))
except sqlalchemy.orm.exc.DetachedInstanceError:
# This happens when the relationship was never loaded and the session is closed.
continue
return {
**base_fields,
**relationships,
Expand Down
17 changes: 8 additions & 9 deletions reflex/state.py
Original file line number Diff line number Diff line change
Expand Up @@ -3438,17 +3438,16 @@ async def set_state(
)

# Recursively set_state on all known substates.
tasks = []
for substate in state.substates.values():
tasks.append(
asyncio.create_task(
self.set_state(
token=_substate_key(client_token, substate),
state=substate,
lock_id=lock_id,
)
tasks = [
asyncio.create_task(
self.set_state(
_substate_key(client_token, substate),
substate,
lock_id,
)
)
for substate in state.substates.values()
]
# Persist only the given state (parents or substates are excluded by BaseState.__getstate__).
if state._get_was_touched():
pickle_state = state._serialize()
Expand Down
6 changes: 3 additions & 3 deletions reflex/utils/processes.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,16 +58,16 @@ def get_process_on_port(port) -> Optional[psutil.Process]:
The process on the given port.
"""
for proc in psutil.process_iter(["pid", "name", "cmdline"]):
try:
with contextlib.suppress(
psutil.NoSuchProcess, psutil.AccessDenied, psutil.ZombieProcess
):
if importlib.metadata.version("psutil") >= "6.0.0":
conns = proc.net_connections(kind="inet") # type: ignore
else:
conns = proc.connections(kind="inet")
for conn in conns:
if conn.laddr.port == int(port):
return proc
except (psutil.NoSuchProcess, psutil.AccessDenied, psutil.ZombieProcess):
pass
return None


Expand Down
7 changes: 3 additions & 4 deletions reflex/utils/pyi_generator.py
Original file line number Diff line number Diff line change
Expand Up @@ -287,10 +287,9 @@ def _generate_docstrings(clzs: list[Type[Component]], props: list[str]) -> str:
for line in (clz.create.__doc__ or "").splitlines():
if "**" in line:
indent = line.split("**")[0]
for nline in [
f"{indent}{n}:{' '.join(c)}" for n, c in props_comments.items()
]:
new_docstring.append(nline)
new_docstring.extend(
[f"{indent}{n}:{' '.join(c)}" for n, c in props_comments.items()]
)
new_docstring.append(line)
return "\n".join(new_docstring)

Expand Down
9 changes: 4 additions & 5 deletions scripts/wait_for_listening_port.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,11 +49,10 @@ def main():
parser.add_argument("--server-pid", type=int)
args = parser.parse_args()
executor = ThreadPoolExecutor(max_workers=len(args.port))
futures = []
for p in args.port:
futures.append(
executor.submit(_wait_for_port, p, args.server_pid, args.timeout)
)
futures = [
executor.submit(_wait_for_port, p, args.server_pid, args.timeout)
for p in args.port
]
for f in as_completed(futures):
ok, msg = f.result()
if ok:
Expand Down
Loading