reflex-hosting-cli 0.1.2__tar.gz → 0.1.3__tar.gz

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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: reflex-hosting-cli
3
- Version: 0.1.2
3
+ Version: 0.1.3
4
4
  Summary: Reflex Hosting CLI
5
5
  Home-page: https://reflex.dev
6
6
  License: Apache-2.0
@@ -19,6 +19,7 @@ Classifier: Programming Language :: Python :: 3.12
19
19
  Requires-Dist: coverage (>=7.3.2,<8.0.0)
20
20
  Requires-Dist: httpx (>=0.24.0,<0.25.0)
21
21
  Requires-Dist: pipdeptree (>=2.13.1,<3.0.0)
22
+ Requires-Dist: pipreqs (>=0.4.13,<0.5.0)
22
23
  Requires-Dist: platformdirs (>=3.10.0,<4.0.0)
23
24
  Requires-Dist: pydantic (>=1.10.2,<2.0.0)
24
25
  Requires-Dist: rich (>=13.0.0,<14.0.0)
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "reflex-hosting-cli"
3
- version = "0.1.2"
3
+ version = "0.1.3"
4
4
  description = "Reflex Hosting CLI"
5
5
  license = "Apache-2.0"
6
6
  authors = [
@@ -33,6 +33,7 @@ websockets = ">=10.4"
33
33
  httpx = "^0.24.0"
34
34
  rich = "^13.0.0"
35
35
  coverage = "^7.3.2"
36
+ pipreqs = "^0.4.13"
36
37
  pipdeptree = "^2.13.1"
37
38
 
38
39
  [tool.poetry.group.dev.dependencies]
@@ -0,0 +1,15 @@
1
+ diff a/reflex_cli/cli.py b/reflex_cli/cli.py (rejected hunks)
2
+ @@ -281,7 +281,12 @@ def deploy(
3
+ # Display the key events such as build, deploy, etc
4
+ # TODO: print logs based on event_id
5
+ server_report_deploy_success = hosting.poll_deploy_milestones(
6
+ - key, from_iso_timestamp=backend_deploy_requested_at
7
+ + key,
8
+ + from_iso_timestamp=backend_deploy_requested_at,
9
+ + deploy_event_ids=[
10
+ + backend_deploy_response.event_id,
11
+ + frontend_deploy_response.event_id,
12
+ + ],
13
+ )
14
+
15
+ if server_report_deploy_success is None:
@@ -32,3 +32,6 @@ class RequirementsTxt(SimpleNamespace):
32
32
 
33
33
  # The requirements.txt file.
34
34
  FILE = "requirements.txt"
35
+
36
+ # Number of unused packages for which we will throw a warning.
37
+ UNUSED_WARN_THRESHOLD = 20
@@ -0,0 +1,136 @@
1
+ """Building the app and initializing all prerequisites."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import difflib
6
+ import os
7
+ import re
8
+ import subprocess
9
+ import sys
10
+ import tempfile
11
+
12
+ from reflex_cli import constants
13
+ from reflex_cli.utils import console
14
+
15
+
16
+ def check_requirements():
17
+ """Check if the requirements.txt needs update based on current environment.
18
+ Throw warnings if too many installed or unused (based on imports) packages in
19
+ the local environment.
20
+ """
21
+ # Run the command and get the output into a temporary requirements.txt file
22
+ tmp_dir = tempfile.mkdtemp()
23
+
24
+ requirements_by_pipreqs_txt = f"{tmp_dir}/requirements_by_pipreqs.txt"
25
+ pipreqs_command = [
26
+ "pipreqs",
27
+ # By default, it runs in the current directory
28
+ "--use-local",
29
+ "--savepath", # Save the file instead of printing to stdout. The print option outputs debug info not sure how to disable.
30
+ requirements_by_pipreqs_txt,
31
+ ]
32
+ console.debug(
33
+ f"Running command to generate requirements using pipreqs to see how many packages are actually used: {pipreqs_command}"
34
+ )
35
+ num_used_packages = None
36
+ try:
37
+ subprocess.run(
38
+ pipreqs_command,
39
+ capture_output=True,
40
+ text=True,
41
+ check=True,
42
+ )
43
+ with open(requirements_by_pipreqs_txt, "r") as f:
44
+ num_used_packages = sum(1 for _ in f)
45
+ console.debug(f"Number of used packages: {num_used_packages}")
46
+ # Clean up the temporary requirements.txt files
47
+ os.remove(requirements_by_pipreqs_txt)
48
+ except subprocess.CalledProcessError as cpe:
49
+ # Only need to log this
50
+ console.debug(f"Unable to run pipreqs util in the subprocess: {cpe}")
51
+ except OSError as ose:
52
+ console.debug(
53
+ f"Unable to interact with pipreqs generated temporary requirements.txt: {ose}"
54
+ )
55
+
56
+ # Run the pipdeptree command and get the output
57
+ try:
58
+ result = subprocess.run(
59
+ [sys.executable, "-m", "pipdeptree", "--warn", "silence"],
60
+ capture_output=True,
61
+ text=True,
62
+ check=True,
63
+ )
64
+ except subprocess.CalledProcessError as cpe:
65
+ console.debug(f"Unable to run pipdeptree util in subprocess: {cpe}")
66
+ console.warn(
67
+ "Unable to detect installed packages in your environment. Please make sure your requirements.txt is up to date."
68
+ )
69
+ return
70
+
71
+ # Filter the output lines using a regular expression
72
+ lines = result.stdout.split("\n")
73
+ new_requirements_lines = []
74
+ for line in lines:
75
+ if re.match(r"^\w+", line):
76
+ new_requirements_lines.append(f"{line}\n")
77
+
78
+ current_requirements_lines = ""
79
+ if os.path.exists(constants.RequirementsTxt.FILE):
80
+ with open(constants.RequirementsTxt.FILE, "r") as f:
81
+ current_requirements_lines = list(f)
82
+ console.debug("Current requirements.txt:")
83
+ console.debug("".join(current_requirements_lines))
84
+
85
+ # Show the differences of current and the newly generated requirements.txt
86
+ diff_content = "".join(
87
+ difflib.unified_diff(
88
+ current_requirements_lines,
89
+ new_requirements_lines,
90
+ fromfile="requirements.txt",
91
+ tofile="new_requirements.txt",
92
+ )
93
+ )
94
+
95
+ if (
96
+ num_used_packages is not None
97
+ and (
98
+ estimated_unused_num_packages := len(new_requirements_lines)
99
+ - num_used_packages
100
+ )
101
+ >= constants.RequirementsTxt.UNUSED_WARN_THRESHOLD
102
+ ):
103
+ console.warn(
104
+ f"Estimated {estimated_unused_num_packages} packages not used. Please make sure your environment is clean."
105
+ )
106
+ if not diff_content:
107
+ console.info("No updates required for the requirements.txt.")
108
+ return
109
+
110
+ if not current_requirements_lines:
111
+ console.info("It seems like there's no requirements.txt in your project.")
112
+ else:
113
+ console.info("The requirements.txt may need to be updated.")
114
+
115
+ console.print(diff_content)
116
+
117
+ user_choice = console.ask(
118
+ "Would you like to update requirements.txt based on the changes above?",
119
+ choices=["y", "n"],
120
+ )
121
+ if user_choice != "y":
122
+ console.warn("Please update requirements.txt manually if needed.")
123
+ # Not exit here since the newly generated requirements.txt is necessarily correct
124
+ # i.e., user enters `n` to override and proceed to deploy
125
+ return
126
+
127
+ # Write the filtered lines to requirements.txt
128
+ try:
129
+ with open(constants.RequirementsTxt.FILE, "w") as f:
130
+ f.writelines(new_requirements_lines)
131
+ console.info("requirements.txt updated.")
132
+ except OSError:
133
+ console.error(
134
+ f"Unable to write to {constants.RequirementsTxt.FILE}. Please manually update it."
135
+ )
136
+ sys.exit(1)
@@ -987,7 +987,7 @@ def interactive_get_deployment_key_from_user_input(
987
987
 
988
988
  # If user takes the suggestion, we will use the suggested key and proceed
989
989
  while key_input := console.ask(
990
- f"Choose a name for your deployed app. Enter to use default.",
990
+ f"Choose a name for your deployed app (https://<picked-name>.reflex.run)\nEnter to use default.",
991
991
  default=key_candidate,
992
992
  ):
993
993
  if not is_valid_deployment_key(key_input):
@@ -1279,7 +1279,7 @@ def prompt_for_regions(
1279
1279
  # Then CP needs to know the user's location, which requires user permission
1280
1280
  while True:
1281
1281
  region_input = console.ask(
1282
- "Region to deploy to. Enter to use default.",
1282
+ "Region to deploy to. See regions: https://bit.ly/46Qr3mF\nEnter to use default.",
1283
1283
  default=regions[0] if regions else "sjc",
1284
1284
  )
1285
1285
 
@@ -1,48 +0,0 @@
1
- """Building the app and initializing all prerequisites."""
2
-
3
- from __future__ import annotations
4
-
5
- import os
6
- import re
7
- import subprocess
8
- import sys
9
-
10
- from reflex_cli import constants
11
- from reflex_cli.utils import console
12
-
13
-
14
- def generate_requirements():
15
- """Generate a requirements.txt file based on the current environment."""
16
- # Run the command and get the output
17
- result = subprocess.run(
18
- [sys.executable, "-m", "pipdeptree", "--warn", "silence"],
19
- capture_output=True,
20
- text=True,
21
- )
22
-
23
- # Filter the output lines using a regular expression
24
- lines = result.stdout.split("\n")
25
- filtered_lines = [line for line in lines if re.match(r"^\w+", line)]
26
-
27
- # Write the filtered lines to requirements.txt
28
- with open("requirements.txt", "w") as f:
29
- for line in filtered_lines:
30
- f.write(line + "\n")
31
-
32
-
33
- def check_requirements():
34
- """Check if the requirements are installed."""
35
- if not os.path.exists(constants.RequirementsTxt.FILE):
36
- console.warn("It seems like there's no requirements.txt in your project.")
37
- response = console.ask(
38
- "Would you like us to auto-generate one based on your current environment?",
39
- choices=["y", "n"],
40
- )
41
-
42
- if response == "y":
43
- generate_requirements()
44
- else:
45
- console.error(
46
- "Please create a requirements.txt file in your project's root directory and try again."
47
- )
48
- exit()