Skip to content

Commit e99dbe2

Browse files
authored
remove psutil as a required dep (except in a windows) (#5498)
* remove psutil as a required dep (except in a windows) * remove maximum for dev * install psutil
1 parent 38bcc06 commit e99dbe2

11 files changed

Lines changed: 27 additions & 75 deletions

File tree

pyproject.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ dependencies = [
2727
"jinja2 >=3.1.2,<4.0",
2828
"packaging >=24.2,<26",
2929
"platformdirs >=4.3.7,<5.0",
30-
"psutil >=7.0.0,<8.0",
30+
"psutil >=7.0.0,<8.0; sys_platform == 'win32'",
3131
"pydantic >=1.10.21,<3.0",
3232
"python-socketio >=5.12.0,<6.0",
3333
"python-multipart >=0.0.20,<1.0",
@@ -165,6 +165,7 @@ dev = [
165165
"playwright >=1.51",
166166
"plotly >=6.0",
167167
"pre-commit ==4.2.0",
168+
"psutil >=7.0.0",
168169
"psycopg[binary] >=3.2",
169170
"pyright >=1.1.400",
170171
"pytest >=8.3",

reflex/istate/manager.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,7 @@ def _default_token_expiration() -> int:
179179

180180
def reset_disk_state_manager():
181181
"""Reset the disk state manager."""
182+
console.debug("Resetting disk state manager.")
182183
states_directory = prerequisites.get_states_dir()
183184
if states_directory.exists():
184185
for path in states_directory.iterdir():

reflex/testing.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@
2424
from pathlib import Path
2525
from typing import TYPE_CHECKING, Any, Literal, TypeVar
2626

27-
import psutil
2827
import uvicorn
2928

3029
import reflex
@@ -478,6 +477,8 @@ def __enter__(self) -> AppHarness:
478477

479478
def stop(self) -> None:
480479
"""Stop the frontend and backend servers."""
480+
import psutil
481+
481482
# Quit browsers first to avoid any lingering events being sent during shutdown.
482483
for driver in self._frontends:
483484
driver.quit()

reflex/utils/exec.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,6 @@
1515
from typing import Any, NamedTuple, TypedDict
1616
from urllib.parse import urljoin
1717

18-
import psutil
19-
2018
from reflex import constants
2119
from reflex.config import get_config
2220
from reflex.constants.base import LogLevel
@@ -131,12 +129,16 @@ def get_changes(old: dict[str, str], new: dict[str, str]) -> Change:
131129
def kill(proc_pid: int):
132130
"""Kills a process and all its child processes.
133131
132+
Requires the `psutil` library to be installed.
133+
134134
Args:
135-
proc_pid (int): The process ID of the process to be killed.
135+
proc_pid: The process ID of the process to be killed.
136136
137137
Example:
138138
>>> kill(1234)
139139
"""
140+
import psutil
141+
140142
process = psutil.Process(proc_pid)
141143
for proc in process.children(recursive=True):
142144
proc.kill()

reflex/utils/prerequisites.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ def check_latest_package_version(package_name: str):
116116
# Get the latest version from PyPI
117117
current_version = importlib.metadata.version(package_name)
118118
url = f"https://pypi.org/pypi/{package_name}/json"
119-
response = net.get(url)
119+
response = net.get(url, timeout=2)
120120
latest_version = response.json()["info"]["version"]
121121
console.debug(f"Latest version of {package_name}: {latest_version}")
122122
if get_or_set_last_reflex_version_check_datetime():

reflex/utils/processes.py

Lines changed: 8 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,17 @@
44

55
import collections
66
import contextlib
7-
import importlib.metadata
87
import os
98
import signal
9+
import socket
1010
import subprocess
1111
from collections.abc import Callable, Generator, Sequence
1212
from concurrent import futures
13+
from contextlib import closing
1314
from pathlib import Path
1415
from typing import Any, Literal, overload
1516

1617
import click
17-
import psutil
1818
from redis.exceptions import RedisError
1919
from rich.progress import Progress
2020

@@ -52,29 +52,6 @@ def get_num_workers() -> int:
5252
return (os.cpu_count() or 1) * 2 + 1
5353

5454

55-
def get_process_on_port(port: int) -> psutil.Process | None:
56-
"""Get the process on the given port.
57-
58-
Args:
59-
port: The port.
60-
61-
Returns:
62-
The process on the given port.
63-
"""
64-
for proc in psutil.process_iter(["pid", "name", "cmdline"]):
65-
with contextlib.suppress(
66-
psutil.NoSuchProcess, psutil.AccessDenied, psutil.ZombieProcess
67-
):
68-
if importlib.metadata.version("psutil") >= "6.0.0":
69-
conns = proc.net_connections(kind="inet")
70-
else:
71-
conns = proc.connections(kind="inet")
72-
for conn in conns:
73-
if conn.laddr.port == int(port):
74-
return proc
75-
return None
76-
77-
7855
def is_process_on_port(port: int) -> bool:
7956
"""Check if a process is running on the given port.
8057
@@ -84,18 +61,8 @@ def is_process_on_port(port: int) -> bool:
8461
Returns:
8562
Whether a process is running on the given port.
8663
"""
87-
return get_process_on_port(port) is not None
88-
89-
90-
def kill_process_on_port(port: int):
91-
"""Kill the process on the given port.
92-
93-
Args:
94-
port: The port.
95-
"""
96-
if get_process_on_port(port) is not None:
97-
with contextlib.suppress(psutil.AccessDenied):
98-
get_process_on_port(port).kill() # pyright: ignore [reportOptionalMemberAccess]
64+
with closing(socket.socket(socket.AF_INET, socket.SOCK_STREAM)) as sock:
65+
return sock.connect_ex(("127.0.0.1", port)) == 0
9966

10067

10168
def change_port(port: int, _type: str) -> int:
@@ -133,13 +100,13 @@ def handle_port(service_name: str, port: int, auto_increment: bool) -> int:
133100
Raises:
134101
Exit:when the port is in use.
135102
"""
136-
if (process := get_process_on_port(port)) is None:
103+
console.debug(f"Checking if {service_name.capitalize()} port: {port} is in use.")
104+
if not is_process_on_port(port):
105+
console.debug(f"{service_name.capitalize()} port: {port} is not in use.")
137106
return port
138107
if auto_increment:
139108
return change_port(port, service_name)
140-
console.error(
141-
f"{service_name.capitalize()} port: {port} is already in use by PID: {process.pid}."
142-
)
109+
console.error(f"{service_name.capitalize()} port: {port} is already in use.")
143110
raise click.exceptions.Exit
144111

145112

reflex/utils/telemetry.py

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@
1313
from typing import TypedDict
1414

1515
import httpx
16-
import psutil
1716

1817
from reflex import constants
1918
from reflex.environment import environment
@@ -89,18 +88,6 @@ def get_reflex_enterprise_version() -> str | None:
8988
return None
9089

9190

92-
def get_memory() -> int:
93-
"""Get the total memory in MB.
94-
95-
Returns:
96-
The total memory in MB.
97-
"""
98-
try:
99-
return psutil.virtual_memory().total >> 20
100-
except ValueError: # needed to pass ubuntu test
101-
return 0
102-
103-
10491
def _raise_on_missing_project_hash() -> bool:
10592
"""Check if an error should be raised when project hash is missing.
10693
@@ -128,7 +115,6 @@ class _Properties(TypedDict):
128115
bun_version: str | None
129116
reflex_enterprise_version: str | None
130117
cpu_count: int
131-
memory: int
132118
cpu_info: dict
133119

134120

@@ -182,7 +168,6 @@ def _get_event_defaults() -> _DefaultEvent | None:
182168
),
183169
"reflex_enterprise_version": get_reflex_enterprise_version(),
184170
"cpu_count": get_cpu_count(),
185-
"memory": get_memory(),
186171
"cpu_info": dataclasses.asdict(cpuinfo) if cpuinfo else {},
187172
},
188173
}

scripts/wait_for_listening_port.py

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,17 +9,12 @@
99
import time
1010
from concurrent.futures import ThreadPoolExecutor, as_completed
1111

12-
# psutil is already a dependency of Reflex itself - so it's OK to use
13-
import psutil
14-
1512

1613
def _pid_exists(pid: int):
17-
# os.kill(pid, 0) doesn't work on Windows (actually kills the PID)
18-
# psutil.pid_exists() doesn't work on Windows (does os.kill underneath)
19-
# psutil.pids() seems to return the right thing. Inefficient but doesn't matter - keeps things simple.
20-
#
2114
# Note: For windows, the pid here is really the "winpid".
22-
return pid in psutil.pids()
15+
import psutil
16+
17+
return psutil.pid_exists(pid)
2318

2419

2520
def _wait_for_port(port: int, server_pid: int, timeout: float) -> tuple[bool, str]:

tests/integration/init-test/in_docker_test_script.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ pip install -U pip
3131
echo "Installing reflex from local repo code"
3232
cp -r /reflex-repo ~/reflex-repo
3333
pip install ~/reflex-repo
34+
pip install psutil
3435

3536
redis-server &
3637

tests/units/test_telemetry.py

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,6 @@ def test_telemetry():
1515
# Check that the CPU count and memory are greater than 0.
1616
assert telemetry.get_cpu_count() > 0
1717

18-
# Check that the available memory is greater than 0
19-
assert telemetry.get_memory() > 0
20-
2118
# Check that the Reflex version is not None.
2219
assert telemetry.get_reflex_version() is not None
2320

0 commit comments

Comments
 (0)