openrewrite-remote 0.14.0__tar.gz → 0.16.0__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.
Files changed (29) hide show
  1. {openrewrite_remote-0.14.0 → openrewrite_remote-0.16.0}/PKG-INFO +2 -2
  2. {openrewrite_remote-0.14.0 → openrewrite_remote-0.16.0}/openrewrite_remote.egg-info/PKG-INFO +2 -2
  3. {openrewrite_remote-0.14.0 → openrewrite_remote-0.16.0}/pyproject.toml +1 -1
  4. {openrewrite_remote-0.14.0 → openrewrite_remote-0.16.0}/rewrite_remote/handlers/list_projects_handler.py +19 -21
  5. {openrewrite_remote-0.14.0 → openrewrite_remote-0.16.0}/rewrite_remote/handlers/parse_project_sources_handler.py +13 -7
  6. {openrewrite_remote-0.14.0 → openrewrite_remote-0.16.0}/rewrite_remote/handlers/project_helper.py +19 -13
  7. {openrewrite_remote-0.14.0 → openrewrite_remote-0.16.0}/rewrite_remote/handlers/recipe_install_handler.py +9 -6
  8. {openrewrite_remote-0.14.0 → openrewrite_remote-0.16.0}/rewrite_remote/handlers/run_recipe_load_and_visitor_handler.py +6 -3
  9. {openrewrite_remote-0.14.0 → openrewrite_remote-0.16.0}/rewrite_remote/receiver.py +1 -0
  10. {openrewrite_remote-0.14.0 → openrewrite_remote-0.16.0}/rewrite_remote/server.py +34 -29
  11. {openrewrite_remote-0.14.0 → openrewrite_remote-0.16.0}/rewrite_remote/type_utils.py +3 -3
  12. {openrewrite_remote-0.14.0 → openrewrite_remote-0.16.0}/README.md +0 -0
  13. {openrewrite_remote-0.14.0 → openrewrite_remote-0.16.0}/openrewrite_remote.egg-info/SOURCES.txt +0 -0
  14. {openrewrite_remote-0.14.0 → openrewrite_remote-0.16.0}/openrewrite_remote.egg-info/dependency_links.txt +0 -0
  15. {openrewrite_remote-0.14.0 → openrewrite_remote-0.16.0}/openrewrite_remote.egg-info/entry_points.txt +0 -0
  16. {openrewrite_remote-0.14.0 → openrewrite_remote-0.16.0}/openrewrite_remote.egg-info/requires.txt +0 -0
  17. {openrewrite_remote-0.14.0 → openrewrite_remote-0.16.0}/openrewrite_remote.egg-info/top_level.txt +0 -0
  18. {openrewrite_remote-0.14.0 → openrewrite_remote-0.16.0}/rewrite_remote/__init__.py +0 -0
  19. {openrewrite_remote-0.14.0 → openrewrite_remote-0.16.0}/rewrite_remote/client.py +0 -0
  20. {openrewrite_remote-0.14.0 → openrewrite_remote-0.16.0}/rewrite_remote/event.py +0 -0
  21. {openrewrite_remote-0.14.0 → openrewrite_remote-0.16.0}/rewrite_remote/handlers/__init__.py +0 -0
  22. {openrewrite_remote-0.14.0 → openrewrite_remote-0.16.0}/rewrite_remote/handlers/handler_helpers.py +0 -0
  23. {openrewrite_remote-0.14.0 → openrewrite_remote-0.16.0}/rewrite_remote/handlers/hello_world_handler.py +0 -0
  24. {openrewrite_remote-0.14.0 → openrewrite_remote-0.16.0}/rewrite_remote/handlers/pypi_manager.py +0 -0
  25. {openrewrite_remote-0.14.0 → openrewrite_remote-0.16.0}/rewrite_remote/handlers/types.py +0 -0
  26. {openrewrite_remote-0.14.0 → openrewrite_remote-0.16.0}/rewrite_remote/remote_utils.py +0 -0
  27. {openrewrite_remote-0.14.0 → openrewrite_remote-0.16.0}/rewrite_remote/remoting.py +0 -0
  28. {openrewrite_remote-0.14.0 → openrewrite_remote-0.16.0}/rewrite_remote/sender.py +0 -0
  29. {openrewrite_remote-0.14.0 → openrewrite_remote-0.16.0}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.2
2
2
  Name: openrewrite-remote
3
- Version: 0.14.0
3
+ Version: 0.16.0
4
4
  Summary: Remoting functionality for the OpenRewrite library.
5
5
  Author-email: "Moderne Inc." <support@moderne.io>
6
6
  License: Moderne, Inc. Commercial License
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.2
2
2
  Name: openrewrite-remote
3
- Version: 0.14.0
3
+ Version: 0.16.0
4
4
  Summary: Remoting functionality for the OpenRewrite library.
5
5
  Author-email: "Moderne Inc." <support@moderne.io>
6
6
  License: Moderne, Inc. Commercial License
@@ -5,7 +5,7 @@ build-backend = "setuptools.build_meta"
5
5
  [project]
6
6
  name = "openrewrite-remote"
7
7
  description = "Remoting functionality for the OpenRewrite library."
8
- version = "0.14.0" # Updated dynamically during release
8
+ version = "0.16.0" # Updated dynamically during release
9
9
  authors = [{ name = "Moderne Inc.", email = "support@moderne.io" }]
10
10
  license = { text = "Moderne, Inc. Commercial License" }
11
11
  dependencies = [
@@ -4,11 +4,14 @@ from io import BytesIO
4
4
  from typing import List
5
5
  from cbor2 import dumps, CBORDecoder
6
6
 
7
- from rewrite_remote.handlers.project_helper import list_projects
7
+ from rewrite_remote.handlers.project_helper import list_sub_projects
8
8
  from rewrite_remote.remote_utils import COMMAND_END
9
9
  from rewrite_remote.remoting import OK, RemotingContext, RemotingMessageType
10
10
  from rewrite_remote.handlers.handler_helpers import respond_with_error
11
11
 
12
+ logger = logging.getLogger("list_projects_handler")
13
+ logger.setLevel(logging.DEBUG)
14
+
12
15
 
13
16
  # Main command handler with the specified signature
14
17
  def list_projects_handler(
@@ -30,37 +33,32 @@ def list_projects_handler(
30
33
  return
31
34
 
32
35
  # 2. Log the request
33
- logging.info(
34
- f"""[Server] Handling install-recipe request: {{
36
+ logger.info(f"""Handling list-recipe request: {{
35
37
  root_project_file: {root_project_file},
36
- }}"""
37
- )
38
+ }}""")
38
39
 
39
40
  # 3. Find projects
40
- projects = list_projects(root_project_file)
41
+ projects = list_sub_projects(root_project_file)
42
+
43
+ project_config_files: List[str] = [root_project_file]
41
44
 
42
- # 4. Log the result
43
- logging.info("[Server] Found %d project(s)", len(projects))
44
45
  for project in projects:
45
- logging.info(
46
- " %s root at %s using %s",
47
- project.project_name,
48
- project.project_root,
49
- project.project_tool,
46
+ project_config_files.append(project.project_root + "/pyproject.toml")
47
+
48
+ # 4. Log the result
49
+ logger.info("Found %d project(s)", len(project_config_files))
50
+ for project in project_config_files:
51
+ logger.info(
52
+ "Found project: %s",
53
+ project,
50
54
  )
51
55
 
52
56
  # 5. Write response to stream
53
- response: List[str] = []
54
-
55
- for project in projects:
56
- response.append(project.project_root)
57
-
58
- # Encode the response using CBOR
59
57
  encoded_response = b""
60
58
  encoded_response += dumps(RemotingMessageType.Response)
61
59
  encoded_response += dumps(OK)
62
- encoded_response += dumps(response)
60
+ encoded_response += dumps(project_config_files)
63
61
  encoded_response += COMMAND_END
64
62
  sock.sendall(encoded_response)
65
63
 
66
- logging.info("[Server] Request completed.")
64
+ logger.info("Request completed.")
@@ -6,7 +6,7 @@ from typing import TypedDict
6
6
 
7
7
  import cbor2
8
8
 
9
- from cbor2 import dumps, CBORDecoder
9
+ from cbor2 import CBORDecoder
10
10
 
11
11
  from rewrite_remote.handlers.project_helper import (
12
12
  find_python_files,
@@ -23,6 +23,9 @@ from rewrite_remote.remoting import RemotingContext
23
23
  from rewrite_remote.handlers.handler_helpers import respond_with_error
24
24
  from rewrite_remote.remoting import RemotingMessenger
25
25
 
26
+ logger = logging.getLogger("parse_project_sources_handler")
27
+ logger.setLevel(logging.DEBUG)
28
+
26
29
 
27
30
  class ParseProjectSourcesArgs(TypedDict):
28
31
  project_file_path: str # The path to the individual pyproject.toml
@@ -69,9 +72,9 @@ def parse_project_sources_handler(
69
72
  return
70
73
 
71
74
  # Log the request
72
- logging.info(
73
- "[Server] Handling parse-project-sources request: {"
74
- "project_file_path: %s, root_project_file_path: %s, repository_dir: %s}",
75
+ logger.info(
76
+ "Handling parse-project-sources request: {\n"
77
+ "\tproject_file_path: %s,\n\t root_project_file_path: %s,\n\t repository_dir: %s\n}",
75
78
  project_file_path,
76
79
  root_project_file_path,
77
80
  repository_dir,
@@ -83,13 +86,16 @@ def parse_project_sources_handler(
83
86
  source_files = parse_python_sources(python_files)
84
87
 
85
88
  # Write the response
89
+ remoting_ctx.reset()
90
+ messenger = RemotingMessenger(remoting_ctx)
86
91
  response_stream = BytesIO()
87
92
  cbor2.dump(RemotingMessageType.Response, response_stream)
88
93
  cbor2.dump(OK, response_stream)
94
+ cbor2.dump(len(source_files), response_stream)
89
95
  for source_file in source_files:
90
- logging.info("Sending ${source_file.source_path}")
91
- RemotingMessenger.send_tree(remoting_ctx, response_stream, source_file, None)
96
+ logger.info("Sending %s", source_file.source_path)
97
+ messenger.send_tree(response_stream, source_file, None)
92
98
  cbor2.dump(COMMAND_END, response_stream)
93
99
  sock.sendall(response_stream.getvalue())
94
100
 
95
- logging.info("[Server] Request completed.")
101
+ logger.info("Request completed.")
@@ -8,7 +8,7 @@ from io import StringIO
8
8
  from rewrite.tree import SourceFile
9
9
  from rewrite.python.parser import PythonParserBuilder
10
10
 
11
- from rewrite import ParserInput, InMemoryExecutionContext
11
+ from rewrite import ParserInput, InMemoryExecutionContext, ExecutionContext
12
12
 
13
13
  from dataclasses import dataclass
14
14
 
@@ -20,7 +20,7 @@ class Project:
20
20
  project_tool: str
21
21
 
22
22
 
23
- def list_projects(pyproject_path: str) -> list[Project]:
23
+ def list_sub_projects(pyproject_path: str) -> list[Project]:
24
24
  """
25
25
  Parses the pyproject.toml file to identify sub projects in a monorepo and returns a list of Projects.
26
26
  """
@@ -35,10 +35,13 @@ def list_projects(pyproject_path: str) -> list[Project]:
35
35
 
36
36
  if is_poetry_project(data):
37
37
  sub_projects = find_sub_projects_in_poetry(data, pyproject_path)
38
+
38
39
  elif is_hatch_project(data):
39
40
  sub_projects = find_sub_projects_in_hatch(data, pyproject_path)
41
+
40
42
  elif is_uv_project(data):
41
43
  sub_projects = find_sub_projects_in_uv_sources(data, pyproject_path)
44
+
42
45
  else:
43
46
  sub_projects = find_sub_projects_in_project_dependencies(data, pyproject_path)
44
47
 
@@ -169,7 +172,7 @@ def find_sub_projects_in_project_dependencies(
169
172
  tomlData: dict[str, Any], toml_path: str
170
173
  ) -> list[Project]:
171
174
  """
172
- Finds sub projects in a project dependencies by looking for dependencies with
175
+ Finds sub-projects in project dependencies by looking for dependencies with
173
176
  the @ file:///${PROJECT_ROOT}//${SUBPROJECT_PATH} format:
174
177
  [project]
175
178
  dependencies = [
@@ -178,16 +181,19 @@ def find_sub_projects_in_project_dependencies(
178
181
  ]
179
182
  """
180
183
  subProjects: list[Project] = []
181
- for dep in tomlData["project"]["dependencies"]:
182
- if isinstance(dep, str) and dep.find("@ file:///${PROJECT_ROOT}//"):
183
- rel_path = dep.split("@ file:///${PROJECT_ROOT}//")[1]
184
- subProjects.append(
185
- Project(
186
- project_name=os.path.basename(dep),
187
- project_root=get_absolute_path(toml_path, rel_path),
188
- project_tool="project.dependencies",
184
+ for dep in tomlData.get("project", {}).get("dependencies", []):
185
+ if isinstance(dep, str) and "@ file:///${PROJECT_ROOT}//" in dep:
186
+ try:
187
+ rel_path = dep.split("@ file:///${PROJECT_ROOT}//", 1)[1]
188
+ subProjects.append(
189
+ Project(
190
+ project_name=os.path.basename(rel_path),
191
+ project_root=get_absolute_path(toml_path, rel_path),
192
+ project_tool="project.dependencies",
193
+ )
189
194
  )
190
- )
195
+ except IndexError:
196
+ print(f"Warning: Unexpected dependency format: {dep}")
191
197
  return subProjects
192
198
 
193
199
 
@@ -222,7 +228,7 @@ def parse_python_sources(paths: List[str]) -> List[SourceFile]:
222
228
  """
223
229
  parser = PythonParserBuilder().build()
224
230
  ctx = InMemoryExecutionContext()
225
-
231
+ ctx.put_message(ExecutionContext.REQUIRE_PRINT_EQUALS_INPUT, False)
226
232
  iterable_source_files: Iterable[SourceFile] = parser.parse_inputs(
227
233
  [
228
234
  ParserInput(
@@ -10,6 +10,9 @@ from rewrite_remote.handlers.handler_helpers import respond_with_error
10
10
  from rewrite_remote.handlers.pypi_manager import PyPiManager, Source
11
11
  from rewrite_remote.handlers.types import PackageSource
12
12
 
13
+ logger = logging.getLogger("recipe_install_handler")
14
+ logger.setLevel(logging.DEBUG)
15
+
13
16
 
14
17
  class RecipeInstallArgs(TypedDict):
15
18
  package_id: str
@@ -81,8 +84,8 @@ def recipe_install_handler(
81
84
  return
82
85
 
83
86
  # 2. Log the request
84
- logging.info(
85
- f"""[Server] Handling install-recipe request: {{
87
+ logger.info(
88
+ f"""Handling install-recipe request: {{
86
89
  packageId: {package_id},
87
90
  packageVersion: {package_version},
88
91
  packageSources: {package_sources},
@@ -117,13 +120,13 @@ def recipe_install_handler(
117
120
  return
118
121
 
119
122
  # 5. Log the result
120
- logging.info(
121
- "[Server] Found %d recipe(s) for package %s",
123
+ logger.info(
124
+ "Found %d recipe(s) for package %s",
122
125
  len(installable_recipes.recipes),
123
126
  package_id,
124
127
  )
125
128
  for recipe in installable_recipes.recipes:
126
- logging.info(" Resolved recipe %s from %s", recipe, valid_source.source)
129
+ logger.info(" Resolved recipe %s from %s", recipe, valid_source.source)
127
130
 
128
131
  # 6. Write response to stream
129
132
  response = {
@@ -147,4 +150,4 @@ def recipe_install_handler(
147
150
  encoded_response += COMMAND_END
148
151
  sock.sendall(encoded_response)
149
152
 
150
- logging.info("[Server] Request completed.")
153
+ logger.info("Request completed.")
@@ -18,6 +18,9 @@ from rewrite_remote.handlers.handler_helpers import respond_with_error
18
18
 
19
19
  from rewrite import InMemoryExecutionContext
20
20
 
21
+ logger = logging.getLogger("run_recipe_load_and_visitor_handler")
22
+ logger.setLevel(logging.DEBUG)
23
+
21
24
 
22
25
  class RunRecipeLoadAndVisitorArgs(TypedDict):
23
26
  recipe_name: str
@@ -68,8 +71,8 @@ def run_recipe_load_and_visitor_handler(
68
71
  return
69
72
 
70
73
  # Log the request
71
- logging.info(
72
- f"""[Server] Handling run-recipe-load-and-visitor request: {{
74
+ logger.info(
75
+ f"""Handling run-recipe-load-and-visitor request: {{
73
76
  recipe_name: {recipe_name},
74
77
  recipe_source: {recipe_source},
75
78
  recipe_options: {recipe_options},
@@ -128,4 +131,4 @@ def run_recipe_load_and_visitor_handler(
128
131
  encoded_response += COMMAND_END
129
132
  sock.sendall(encoded_response)
130
133
 
131
- logging.info("[Server] Request completed.")
134
+ logger.info("Request completed.")
@@ -524,6 +524,7 @@ def _decode_length(
524
524
  else:
525
525
  raise CBORDecodeValueError(f"unknown unsigned integer subtype 0x{subtype:x}")
526
526
 
527
+
527
528
  class ParseErrorReceiver(Receiver):
528
529
  def fork(self, ctx):
529
530
  return ctx.fork(self.Visitor(), self.Factory())
@@ -1,7 +1,9 @@
1
1
  # type: ignore
2
2
  import importlib
3
3
  import importlib.resources
4
+ import logging
4
5
  import os
6
+ import select
5
7
  import socket
6
8
  import sys
7
9
  import time
@@ -10,21 +12,7 @@ import zipfile
10
12
  from io import BytesIO, StringIO
11
13
 
12
14
  import cbor2
13
- import select
14
15
  from cbor2 import dumps
15
- from rewrite import (
16
- ParserInput,
17
- InMemoryExecutionContext,
18
- ExecutionContext,
19
- ParseError,
20
- Recipe,
21
- )
22
- from rewrite.java.remote import *
23
- from rewrite.python import Py
24
- from rewrite.python.parser import PythonParserBuilder
25
- from rewrite.python.remote.receiver import PythonReceiver
26
- from rewrite.python.remote.sender import PythonSender
27
-
28
16
  from rewrite_remote.handlers.hello_world_handler import hello_world_handler
29
17
  from rewrite_remote.handlers.list_projects_handler import list_projects_handler
30
18
  from rewrite_remote.handlers.parse_project_sources_handler import (
@@ -37,20 +25,41 @@ from rewrite_remote.handlers.recipe_install_handler import (
37
25
  from rewrite_remote.handlers.run_recipe_load_and_visitor_handler import (
38
26
  run_recipe_load_and_visitor_handler,
39
27
  )
40
- from rewrite_remote.receiver import ReceiverContext
41
28
  from rewrite_remote.remoting import (
42
29
  RemotePrinterFactory,
43
30
  RemotingContext,
44
31
  RemotingMessageType,
45
32
  RemotingMessenger,
46
33
  )
47
- from rewrite_remote.sender import ParseErrorSender, SenderContext
34
+ from rewrite_remote.sender import ParseErrorSender
35
+
36
+ from rewrite import (
37
+ ParserInput,
38
+ InMemoryExecutionContext,
39
+ ExecutionContext,
40
+ ParseError,
41
+ Recipe,
42
+ )
43
+ from rewrite.java.remote import *
44
+ from rewrite.python import Py
45
+ from rewrite.python.parser import PythonParserBuilder
46
+ from rewrite.python.remote.receiver import PythonReceiver
47
+ from rewrite.python.remote.sender import PythonSender
48
48
 
49
49
  INACTIVITY_TIMEOUT = 300 # 5 minutes
50
50
  _OK: int = 0
51
51
  _ERROR: int = 1
52
52
 
53
53
 
54
+ # Configure logging
55
+ logging.basicConfig(
56
+ level=logging.DEBUG,
57
+ format="%(asctime)s - %(levelname)s - %(message)s",
58
+ )
59
+ logger = logging.getLogger("server")
60
+ logger.setLevel(logging.DEBUG)
61
+
62
+
54
63
  def register_remoting_factories() -> None:
55
64
  SenderContext.register(ParseError, ParseErrorSender)
56
65
  SenderContext.register(Py, PythonSender)
@@ -109,7 +118,7 @@ class Server:
109
118
  with socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) as s:
110
119
  s.bind(self._path)
111
120
  s.listen()
112
- print(f"Server listening on Unix domain socket: {self._path}")
121
+ logger.info(f"Server listening on Unix domain socket: {self._path}")
113
122
  while True:
114
123
  conn, _ = s.accept()
115
124
  with conn:
@@ -119,7 +128,7 @@ class Server:
119
128
  s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
120
129
  s.bind(("localhost", self._port))
121
130
  s.listen(5)
122
- print(f"Server listening on port {self._port}")
131
+ logger.info(f"Server listening on port {self._port}")
123
132
  last_activity_time = time.time()
124
133
  while True:
125
134
  s.settimeout(5)
@@ -132,7 +141,7 @@ class Server:
132
141
  except socket.timeout:
133
142
  current_time = time.time()
134
143
  if current_time - last_activity_time >= self.timeout:
135
- print("No new connections for 5 minutes, shutting down server.")
144
+ logger.info("No new connections for 5 minutes, shutting down server.")
136
145
  break
137
146
 
138
147
  def handle_client(self, sock: socket.socket) -> None:
@@ -148,15 +157,11 @@ class Server:
148
157
  assert cbor2.load(BytesIO(message_type)) == RemotingMessageType.Request
149
158
  self._messenger.process_request(sock)
150
159
 
151
- readable, _, _ = select.select([sock], [], [], 0.01)
152
- if sock not in readable:
153
- return
154
-
155
160
  except (OSError, IOError):
156
- # the socket was closed
161
+ logger.error("Socket was closed unexpectedly")
157
162
  return
158
163
  except Exception as e:
159
- print(f"An error occurred while handling client: {e}")
164
+ logger.error(f"An error occurred while handling client: {e}")
160
165
  traceback.print_exc()
161
166
  if sock.fileno() != -1:
162
167
  try:
@@ -165,12 +170,12 @@ class Server:
165
170
  sock.send(dumps(_ERROR))
166
171
  sock.send(dumps(traceback.format_exc()))
167
172
  except (OSError, IOError):
168
- # the socket was closed
173
+ logger.error("Failed to send error response, socket was closed")
169
174
  return
170
175
  except Exception as inner_exception:
171
- print(inner_exception)
172
- finally:
173
- sock.close()
176
+ logger.error(
177
+ f"An error occurred while sending error response: {inner_exception}"
178
+ )
174
179
 
175
180
  def parse_python_source(
176
181
  self,
@@ -108,6 +108,6 @@ def __convert_snake_to_camel(field_name: str) -> str:
108
108
 
109
109
  def get_type(type_name: str) -> Type[Any]:
110
110
  # `type_name` will look like `org.openrewrite.java.tree.J$CompilationUnit`
111
- parts = type_name.split('.')
112
- module = importlib.import_module('rewrite.' + parts[2])
113
- return getattr(module, parts[-1].split('$')[1])
111
+ parts = type_name.split(".")
112
+ module = importlib.import_module("rewrite." + parts[2])
113
+ return getattr(module, parts[-1].split("$")[1])