waldiez 0.4.4__py3-none-any.whl → 0.4.6__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of waldiez might be problematic. Click here for more details.

Files changed (54) hide show
  1. waldiez/__init__.py +18 -10
  2. waldiez/_version.py +5 -2
  3. waldiez/cli.py +19 -4
  4. waldiez/exporter.py +8 -4
  5. waldiez/exporting/agent/utils/captain_agent.py +4 -1
  6. waldiez/exporting/agent/utils/group_manager.py +0 -1
  7. waldiez/exporting/agent/utils/rag_user/rag_user.py +1 -0
  8. waldiez/exporting/agent/utils/swarm_agent.py +1 -0
  9. waldiez/exporting/base/base_exporter.py +2 -2
  10. waldiez/exporting/base/mixin.py +3 -0
  11. waldiez/exporting/base/utils/comments.py +2 -0
  12. waldiez/exporting/chats/utils/sequential.py +1 -1
  13. waldiez/exporting/chats/utils/single_chat.py +3 -0
  14. waldiez/exporting/chats/utils/swarm.py +3 -0
  15. waldiez/exporting/flow/flow_exporter.py +2 -0
  16. waldiez/exporting/flow/utils/def_main.py +1 -0
  17. waldiez/exporting/flow/utils/flow_content.py +3 -0
  18. waldiez/exporting/flow/utils/flow_names.py +1 -0
  19. waldiez/exporting/flow/utils/importing_utils.py +1 -0
  20. waldiez/exporting/flow/utils/logging_utils.py +8 -8
  21. waldiez/exporting/skills/skills_exporter.py +1 -1
  22. waldiez/exporting/skills/utils.py +5 -3
  23. waldiez/models/__init__.py +1 -0
  24. waldiez/models/agents/agent/agent.py +1 -1
  25. waldiez/models/agents/agent/termination_message.py +1 -0
  26. waldiez/models/agents/group_manager/speakers.py +1 -1
  27. waldiez/models/agents/rag_user/retrieve_config.py +1 -0
  28. waldiez/models/agents/swarm_agent/after_work.py +0 -1
  29. waldiez/models/agents/swarm_agent/on_condition.py +1 -0
  30. waldiez/models/agents/swarm_agent/on_condition_available.py +1 -0
  31. waldiez/models/chat/chat.py +2 -0
  32. waldiez/models/chat/chat_message.py +1 -0
  33. waldiez/models/common/ag2_version.py +2 -2
  34. waldiez/models/common/method_utils.py +11 -2
  35. waldiez/models/flow/flow.py +1 -0
  36. waldiez/models/model/extra_requirements.py +2 -2
  37. waldiez/models/skill/extra_requirements.py +3 -6
  38. waldiez/models/waldiez.py +9 -8
  39. waldiez/runner.py +4 -2
  40. waldiez/running/__init__.py +2 -0
  41. waldiez/running/environment.py +21 -1
  42. waldiez/running/gen_seq_diagram.py +3 -2
  43. waldiez/running/running.py +3 -2
  44. waldiez/utils/__init__.py +2 -0
  45. waldiez/utils/conflict_checker.py +3 -3
  46. waldiez/utils/pysqlite3_checker.py +63 -21
  47. waldiez/utils/rdps_checker.py +122 -0
  48. {waldiez-0.4.4.dist-info → waldiez-0.4.6.dist-info}/METADATA +109 -41
  49. {waldiez-0.4.4.dist-info → waldiez-0.4.6.dist-info}/RECORD +53 -52
  50. {waldiez-0.4.4.dist-info → waldiez-0.4.6.dist-info}/licenses/LICENSE +2 -2
  51. waldiez-0.4.6.dist-info/licenses/NOTICE.md +14 -0
  52. waldiez-0.4.4.dist-info/licenses/NOTICE.md +0 -5
  53. {waldiez-0.4.4.dist-info → waldiez-0.4.6.dist-info}/WHEEL +0 -0
  54. {waldiez-0.4.4.dist-info → waldiez-0.4.6.dist-info}/entry_points.txt +0 -0
@@ -39,11 +39,11 @@ def get_models_extra_requirements(
39
39
  for requirement in model.requirements:
40
40
  model_requirements.add(requirement)
41
41
  if model.data.api_type == "google":
42
- model_requirements.add(f"pyautogen[gemini]=={autogen_version}")
42
+ model_requirements.add(f"ag2[gemini]=={autogen_version}")
43
43
  continue
44
44
  if model.data.api_type in models_with_additional_requirements:
45
45
  model_requirements.add(
46
- f"pyautogen[{model.data.api_type}]=={autogen_version}"
46
+ f"ag2[{model.data.api_type}]=={autogen_version}"
47
47
  )
48
48
  return model_requirements
49
49
 
@@ -19,6 +19,7 @@ def get_skills_extra_requirements(
19
19
  The skills.
20
20
  autogen_version : str
21
21
  The ag2 version.
22
+
22
23
  Returns
23
24
  -------
24
25
  List[str]
@@ -27,13 +28,9 @@ def get_skills_extra_requirements(
27
28
  skill_requirements: Set[str] = set()
28
29
  for skill in skills:
29
30
  if skill.skill_type == "langchain":
30
- skill_requirements.add(
31
- f"pyautogen[interop-langchain]=={autogen_version}"
32
- )
31
+ skill_requirements.add(f"ag2[interop-langchain]=={autogen_version}")
33
32
  if skill.skill_type == "crewai":
34
- skill_requirements.add(
35
- f"pyautogen[interop-crewai]=={autogen_version}"
36
- )
33
+ skill_requirements.add(f"ag2[interop-crewai]=={autogen_version}")
37
34
  for requirement in skill.requirements:
38
35
  skill_requirements.add(requirement)
39
36
  return skill_requirements
waldiez/models/waldiez.py CHANGED
@@ -1,6 +1,6 @@
1
1
  # SPDX-License-Identifier: Apache-2.0.
2
2
  # Copyright (c) 2024 - 2025 Waldiez and contributors.
3
- """Waldiez
3
+ """Waldiez data class.
4
4
 
5
5
  A Waldiez class contains all the information that is needed to generate
6
6
  and run an autogen workflow. It has the model/LLM configurations, the agent
@@ -167,7 +167,7 @@ class Waldiez:
167
167
  """Get the agents.
168
168
 
169
169
  Yields
170
- -------
170
+ ------
171
171
  WaldiezAgent
172
172
  The flow agents.
173
173
  """
@@ -178,7 +178,7 @@ class Waldiez:
178
178
  """Get the flow skills.
179
179
 
180
180
  Yields
181
- -------
181
+ ------
182
182
  WaldiezSkill
183
183
  The skills.
184
184
  """
@@ -189,7 +189,7 @@ class Waldiez:
189
189
  """Get the models.
190
190
 
191
191
  Yields
192
- -------
192
+ ------
193
193
  WaldiezModel
194
194
  The flow models.
195
195
  """
@@ -230,8 +230,9 @@ class Waldiez:
230
230
  """Get the flow requirements."""
231
231
  autogen_version = get_autogen_version()
232
232
  requirements_list = filter(
233
- # we use the fixed "pyautogen=={autogen_version}" below
233
+ # we use the fixed "ag2=={autogen_version}" below
234
234
  lambda requirement: not (
235
+ # cspell:disable-next-line
235
236
  requirement.startswith("pyautogen")
236
237
  or requirement.startswith("ag2")
237
238
  or requirement.startswith("autogen")
@@ -239,12 +240,12 @@ class Waldiez:
239
240
  self.flow.requirements,
240
241
  )
241
242
  requirements = set(requirements_list)
242
- requirements.add(f"pyautogen[openai]=={autogen_version}")
243
+ requirements.add(f"ag2[openai]=={autogen_version}")
243
244
  if self.has_rag_agents:
244
245
  rag_extras = get_retrievechat_extra_requirements(self.agents)
245
246
  requirements.update(rag_extras)
246
247
  if self.has_multimodal_agents:
247
- requirements.add(f"pyautogen[lmm]=={autogen_version}")
248
+ requirements.add(f"ag2[lmm]=={autogen_version}")
248
249
  if self.has_captain_agents:
249
250
  # pysqlite3-binary might not get installed on windows
250
251
  captain_extras = [
@@ -276,7 +277,7 @@ class Waldiez:
276
277
  autogen_version=autogen_version,
277
278
  )
278
279
  )
279
- return sorted(list(requirements))
280
+ return sorted(requirements)
280
281
 
281
282
  def get_flow_env_vars(self) -> List[Tuple[str, str]]:
282
283
  """Get the flow environment variables.
waldiez/runner.py CHANGED
@@ -1,6 +1,7 @@
1
1
  # SPDX-License-Identifier: Apache-2.0.
2
2
  # Copyright (c) 2024 - 2025 Waldiez and contributors.
3
3
  """Run a waldiez flow.
4
+
4
5
  The flow is first converted to an autogen flow with agents, chats and skills.
5
6
  We then chown to temporary directory, call the flow's `main()` and
6
7
  return the results. Before running the flow, any additional environment
@@ -144,9 +145,9 @@ class WaldiezRunner:
144
145
  Set[str]
145
146
  The extra requirements.
146
147
  """
147
- extra_requirements = set(
148
+ extra_requirements = {
148
149
  req for req in self.waldiez.requirements if req not in sys.modules
149
- )
150
+ }
150
151
  if self.waldiez.has_captain_agents:
151
152
  check_pysqlite3()
152
153
  return extra_requirements
@@ -185,6 +186,7 @@ class WaldiezRunner:
185
186
  The runtime uploads root.
186
187
  skip_mmd : bool
187
188
  Whether to skip the Mermaid diagram generation.
189
+
188
190
  Returns
189
191
  -------
190
192
  Union[ChatResult, List[ChatResult]]
@@ -4,6 +4,7 @@
4
4
 
5
5
  from .environment import (
6
6
  in_virtualenv,
7
+ is_root,
7
8
  refresh_environment,
8
9
  reset_env_vars,
9
10
  set_env_vars,
@@ -26,6 +27,7 @@ __all__ = [
26
27
  "chdir",
27
28
  "get_printer",
28
29
  "in_virtualenv",
30
+ "is_root",
29
31
  "install_requirements",
30
32
  "refresh_environment",
31
33
  "reset_env_vars",
@@ -25,6 +25,26 @@ def in_virtualenv() -> bool:
25
25
  )
26
26
 
27
27
 
28
+ def is_root() -> bool:
29
+ """Check if the script is running as root/administrator.
30
+
31
+ Returns
32
+ -------
33
+ bool
34
+ True if running as root/administrator, False otherwise.
35
+ """
36
+ # pylint: disable=import-outside-toplevel,line-too-long
37
+ if os.name == "nt":
38
+ try:
39
+ import ctypes
40
+
41
+ return ctypes.windll.shell32.IsUserAnAdmin() != 0 # type: ignore[unused-ignore,attr-defined] # noqa: E501
42
+ except Exception: # pylint: disable=broad-exception-caught
43
+ return False
44
+ else:
45
+ return os.getuid() == 0
46
+
47
+
28
48
  def refresh_environment() -> None:
29
49
  """Refresh the environment."""
30
50
  with warnings.catch_warnings():
@@ -70,7 +90,7 @@ def refresh_environment() -> None:
70
90
 
71
91
  @contextlib.contextmanager
72
92
  def _np_no_nep50_warning() -> Generator[None, None, None]:
73
- """Dummy function to avoid the warning.
93
+ """Avoid no_nep50 warning.
74
94
 
75
95
  Yields
76
96
  ------
@@ -69,12 +69,12 @@ def process_events(df_events: pd.DataFrame) -> str:
69
69
  ----------
70
70
  df_events : pd.DataFrame
71
71
  The DataFrame containing the events data.
72
+
72
73
  Returns
73
74
  -------
74
75
  str
75
76
  The Mermaid sequence diagram text.
76
77
  """
77
-
78
78
  # Set to store participants (senders and recipients)
79
79
  participants: Set[str] = set()
80
80
  recipient: str
@@ -150,7 +150,7 @@ def save_diagram(mermaid_text: str, output_path: Union[str, Path]) -> None:
150
150
  def generate_sequence_diagram(
151
151
  file_path: Union[str, Path], output_path: Union[str, Path]
152
152
  ) -> None:
153
- """Main function to generate the Mermaid diagram.
153
+ """Generate the Mermaid diagram.
154
154
 
155
155
  Parameters
156
156
  ----------
@@ -163,6 +163,7 @@ def generate_sequence_diagram(
163
163
  ------
164
164
  FileNotFoundError
165
165
  If the input file is not found.
166
+
166
167
  ValueError
167
168
  If the input file is not a JSON or CSV file.
168
169
  """
@@ -23,7 +23,7 @@ from typing import (
23
23
  Union,
24
24
  )
25
25
 
26
- from .environment import in_virtualenv
26
+ from .environment import in_virtualenv, is_root
27
27
  from .gen_seq_diagram import generate_sequence_diagram
28
28
 
29
29
  # pylint: disable=import-outside-toplevel
@@ -126,7 +126,8 @@ def install_requirements(
126
126
  # but it might fail if we don't
127
127
  break_system_packages = os.environ.get("PIP_BREAK_SYSTEM_PACKAGES", "")
128
128
  os.environ["PIP_BREAK_SYSTEM_PACKAGES"] = "1"
129
- pip_install.append("--user")
129
+ if not is_root():
130
+ pip_install.append("--user")
130
131
  pip_install.extend(extra_requirements)
131
132
  # pylint: disable=too-many-try-statements
132
133
  try:
waldiez/utils/__init__.py CHANGED
@@ -6,10 +6,12 @@ from .cli_extras import add_cli_extras
6
6
  from .conflict_checker import check_conflicts
7
7
  from .flaml_warnings import check_flaml_warnings
8
8
  from .pysqlite3_checker import check_pysqlite3
9
+ from .rdps_checker import check_rpds_py
9
10
 
10
11
  __all__ = [
11
12
  "check_conflicts",
12
13
  "check_flaml_warnings",
13
14
  "add_cli_extras",
14
15
  "check_pysqlite3",
16
+ "check_rpds_py",
15
17
  ]
@@ -17,11 +17,11 @@ def _check_conflicts() -> None: # pragma: no cover
17
17
  print(
18
18
  "Conflict detected: 'autogen-agentchat' is installed "
19
19
  "in the current environment, \n"
20
- "which conflicts with 'ag2' / 'pyautogen'.\n"
20
+ "which conflicts with 'ag2'.\n"
21
21
  "Please uninstall 'autogen-agentchat': \n"
22
22
  f"{sys.executable} -m pip uninstall -y autogen-agentchat" + "\n"
23
- "And install 'pyautogen' (and/or 'waldiez') again: \n"
24
- f"{sys.executable} -m pip install --force pyautogen waldiez",
23
+ "And install 'ag2' (and/or 'waldiez') again: \n"
24
+ f"{sys.executable} -m pip install --force ag2 waldiez",
25
25
  file=sys.stderr,
26
26
  )
27
27
  sys.exit(1)
@@ -8,6 +8,7 @@ Highly recommended to be run in a virtual environment.
8
8
  'setuptools' and 'wheel' will also be installed if not already installed.
9
9
  """
10
10
 
11
+ import contextlib
11
12
  import os
12
13
  import platform
13
14
  import shutil
@@ -22,10 +23,10 @@ PYSQLITE3_VERSION = "0.5.4"
22
23
  SQLITE_URL = "https://www.sqlite.org/2025/sqlite-amalgamation-3480000.zip"
23
24
  PYSQLITE3_URL = f"https://github.com/coleifer/pysqlite3/archive/refs/tags/{PYSQLITE3_VERSION}.zip" # pylint: disable=line-too-long
24
25
 
25
- PIP = f"{sys.executable} -m pip"
26
+ PIP = [sys.executable, "-m", "pip"]
26
27
 
27
28
 
28
- def run_command(command: str, cwd: str = ".") -> None:
29
+ def run_command(command: list[str], cwd: str = ".") -> None:
29
30
  """Run a command.
30
31
 
31
32
  Parameters
@@ -35,12 +36,11 @@ def run_command(command: str, cwd: str = ".") -> None:
35
36
  cwd : str
36
37
  The current working directory.
37
38
  """
38
- cmd_parts = command.split(" ")
39
39
  if cwd == ".":
40
40
  cwd = os.getcwd()
41
41
  try:
42
42
  subprocess.run( # nosemgrep # nosec
43
- cmd_parts,
43
+ command,
44
44
  check=True,
45
45
  cwd=cwd,
46
46
  env=os.environ,
@@ -64,6 +64,26 @@ def in_virtualenv() -> bool:
64
64
  )
65
65
 
66
66
 
67
+ def is_root() -> bool:
68
+ """Check if the script is running as root/administrator.
69
+
70
+ Returns
71
+ -------
72
+ bool
73
+ True if running as root/administrator, False otherwise.
74
+ """
75
+ # pylint: disable=import-outside-toplevel,line-too-long
76
+ if os.name == "nt":
77
+ try:
78
+ import ctypes
79
+
80
+ return ctypes.windll.shell32.IsUserAnAdmin() != 0 # type: ignore[unused-ignore,attr-defined] # noqa: E501
81
+ except Exception: # pylint: disable=broad-exception-caught
82
+ return False
83
+ else:
84
+ return os.getuid() == 0
85
+
86
+
67
87
  def pip_install(*package_names: str, cwd: str = ".") -> None:
68
88
  """Install packages using pip.
69
89
 
@@ -74,11 +94,19 @@ def pip_install(*package_names: str, cwd: str = ".") -> None:
74
94
  cwd : str
75
95
  The current working directory.
76
96
  """
77
- args = "-qq"
97
+ args = ["install", "-qq"]
98
+ break_system_packages = ""
99
+ if not in_virtualenv():
100
+ break_system_packages = os.environ.get("PIP_BREAK_SYSTEM_PACKAGES", "")
101
+ os.environ["PIP_BREAK_SYSTEM_PACKAGES"] = "1"
102
+ if not is_root():
103
+ args.append("--user")
104
+ run_command(PIP + args + list(package_names), cwd)
78
105
  if not in_virtualenv():
79
- args += " --user --break-system-packages"
80
- package_names_str = " ".join(package_names)
81
- run_command(f"{PIP} install {args} {package_names_str}", cwd)
106
+ if break_system_packages:
107
+ os.environ["PIP_BREAK_SYSTEM_PACKAGES"] = break_system_packages
108
+ else:
109
+ os.environ.pop("PIP_BREAK_SYSTEM_PACKAGES", None)
82
110
 
83
111
 
84
112
  def pip_uninstall(*package_names: str, cwd: str = ".") -> None:
@@ -91,11 +119,17 @@ def pip_uninstall(*package_names: str, cwd: str = ".") -> None:
91
119
  cwd : str
92
120
  The current working directory.
93
121
  """
94
- args = "-qq --yes"
122
+ args = ["uninstall", "-qq", "--yes"]
123
+ break_system_packages = ""
95
124
  if not in_virtualenv():
96
- args += " --break-system-packages"
97
- package_names_str = " ".join(package_names)
98
- run_command(f"{PIP} uninstall {args} {package_names_str}", cwd)
125
+ break_system_packages = os.environ.get("PIP_BREAK_SYSTEM_PACKAGES", "")
126
+ os.environ["PIP_BREAK_SYSTEM_PACKAGES"] = "1"
127
+ run_command(PIP + args + list(package_names), cwd)
128
+ if not in_virtualenv():
129
+ if break_system_packages:
130
+ os.environ["PIP_BREAK_SYSTEM_PACKAGES"] = break_system_packages
131
+ else:
132
+ os.environ.pop("PIP_BREAK_SYSTEM_PACKAGES", None)
99
133
 
100
134
 
101
135
  def download_sqlite_amalgamation() -> str:
@@ -187,15 +221,23 @@ def install_pysqlite3(sqlite_amalgamation_path: str) -> None:
187
221
  try:
188
222
  pysqlite3_dir = prepare_pysqlite3(sqlite_amalgamation_path)
189
223
  pip_install("setuptools")
190
- run_command(f"{sys.executable} setup.py build_static", pysqlite3_dir)
191
- pip_install("wheel")
192
- run_command(
193
- f"{PIP} wheel . -w dist",
194
- pysqlite3_dir,
195
- )
196
- wheel_file = os.listdir(os.path.join(pysqlite3_dir, "dist"))[0]
197
- wheel_path = os.path.join("dist", wheel_file)
198
- pip_install(wheel_path, cwd=pysqlite3_dir)
224
+ # let's suppress logs
225
+ with open(os.devnull, "w", encoding="utf-8") as devnull:
226
+ with (
227
+ contextlib.redirect_stdout(devnull),
228
+ contextlib.redirect_stderr(devnull),
229
+ ):
230
+ run_command(
231
+ [sys.executable, "setup.py", "build_static"], pysqlite3_dir
232
+ )
233
+ pip_install("wheel")
234
+ run_command(
235
+ PIP + ["wheel", ".", "-w", "dist"],
236
+ pysqlite3_dir,
237
+ )
238
+ wheel_file = os.listdir(os.path.join(pysqlite3_dir, "dist"))[0]
239
+ wheel_path = os.path.join("dist", wheel_file)
240
+ pip_install(wheel_path, cwd=pysqlite3_dir)
199
241
  except BaseException as e: # pylint: disable=broad-except
200
242
  print(f"Failed to install pysqlite3: {e}")
201
243
  sys.exit(1)
@@ -0,0 +1,122 @@
1
+ # SPDX-License-Identifier: Apache-2.0.
2
+ # Copyright (c) 2024 - 2025 Waldiez and contributors.
3
+ """
4
+ Check for rpds-py on Windows ARM64.
5
+
6
+ Since we cannot use direct git dependency for `rpds-py` in `pyproject.toml`,
7
+ let's check it here.
8
+
9
+ NOTE: We should regularly check if this is still needed.
10
+ """
11
+ # pylint: disable=import-outside-toplevel,unused-import
12
+
13
+ # "rpds-py @ git+https://github.com/crate-py/rpds.git@v0.24.0 ;
14
+ # sys_platform == "win32" and platform_machine == "AARCH64"",
15
+
16
+ import os
17
+ import platform
18
+ import subprocess
19
+ import sys
20
+
21
+ PIP = [sys.executable, "-m", "pip"]
22
+ RDPS_PY_VERSION = "0.24.0"
23
+ RDPS_PY_URL = f"git+https://github.com/crate-py/rpds.git@{RDPS_PY_VERSION}"
24
+
25
+
26
+ def is_windows_arm64() -> bool:
27
+ """Check if the current platform is Windows ARM64.
28
+
29
+ Returns
30
+ -------
31
+ bool
32
+ True if the platform is Windows ARM64, False otherwise.
33
+ """
34
+ return sys.platform == "win32" and platform.machine().lower() in [
35
+ "arm64",
36
+ "aarch64",
37
+ ]
38
+
39
+
40
+ def is_rpds_py_installed() -> bool:
41
+ """Check if `rpds-py` is installed.
42
+
43
+ Returns
44
+ -------
45
+ bool
46
+ True if `rpds-py` is installed, False otherwise.
47
+ """
48
+ try:
49
+ import rpds # noqa: F401
50
+
51
+ return True
52
+ except ImportError:
53
+ return False
54
+
55
+
56
+ def is_root() -> bool:
57
+ """Check if the script is running as root/administrator.
58
+
59
+ Returns
60
+ -------
61
+ bool
62
+ True if running as root/administrator, False otherwise.
63
+ """
64
+ # pylint: disable=import-outside-toplevel,line-too-long
65
+ if os.name == "nt":
66
+ try:
67
+ import ctypes
68
+
69
+ return ctypes.windll.shell32.IsUserAnAdmin() != 0 # type: ignore[unused-ignore,attr-defined] # noqa: E501
70
+ except Exception: # pylint: disable=broad-exception-caught
71
+ return False
72
+ else:
73
+ return os.getuid() == 0
74
+
75
+
76
+ def in_virtualenv() -> bool:
77
+ """Check if the current environment is a virtual environment.
78
+
79
+ Returns
80
+ -------
81
+ bool
82
+ True if in a virtual environment, False otherwise.
83
+ """
84
+ return hasattr(sys, "real_prefix") or (
85
+ hasattr(sys, "base_prefix")
86
+ and os.path.realpath(sys.base_prefix) != os.path.realpath(sys.prefix)
87
+ )
88
+
89
+
90
+ def install_rpds_py() -> None:
91
+ """Install `rpds-py`."""
92
+ command = PIP + ["install", "-qq"]
93
+ if not in_virtualenv():
94
+ break_system_packages = os.environ.get("PIP_BREAK_SYSTEM_PACKAGES", "")
95
+ os.environ["PIP_BREAK_SYSTEM_PACKAGES"] = "1"
96
+ if not is_root():
97
+ command.append("--user")
98
+ command.append(RDPS_PY_URL)
99
+ try:
100
+ subprocess.check_call(command)
101
+ except subprocess.CalledProcessError as e:
102
+ print(f"Failed to install rpds-py: {e}")
103
+ finally:
104
+ if not in_virtualenv():
105
+ # restore the old env var
106
+ if break_system_packages:
107
+ os.environ["PIP_BREAK_SYSTEM_PACKAGES"] = break_system_packages
108
+ else:
109
+ del os.environ["PIP_BREAK_SYSTEM_PACKAGES"]
110
+
111
+
112
+ def check_rpds_py() -> None:
113
+ """Check if `rpds-py` is installed on Windows ARM64."""
114
+ if not is_windows_arm64():
115
+ return
116
+ if is_rpds_py_installed():
117
+ return
118
+ install_rpds_py()
119
+
120
+
121
+ if __name__ == "__main__":
122
+ check_rpds_py()