openrewrite-migrate-python 0.1.0__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.
Files changed (68) hide show
  1. openrewrite_migrate_python/__init__.py +35 -0
  2. openrewrite_migrate_python/migrate/__init__.py +219 -0
  3. openrewrite_migrate_python/migrate/aifc_migrations.py +517 -0
  4. openrewrite_migrate_python/migrate/array_deprecations.py +133 -0
  5. openrewrite_migrate_python/migrate/ast_deprecations.py +322 -0
  6. openrewrite_migrate_python/migrate/asyncio_coroutine_to_async.py +225 -0
  7. openrewrite_migrate_python/migrate/asyncio_deprecations.py +117 -0
  8. openrewrite_migrate_python/migrate/calendar_deprecations.py +134 -0
  9. openrewrite_migrate_python/migrate/cgi_migrations.py +213 -0
  10. openrewrite_migrate_python/migrate/cgi_parse_deprecations.py +170 -0
  11. openrewrite_migrate_python/migrate/collections_abc_migrations.py +207 -0
  12. openrewrite_migrate_python/migrate/configparser_deprecations.py +252 -0
  13. openrewrite_migrate_python/migrate/datetime_utc.py +136 -0
  14. openrewrite_migrate_python/migrate/distutils_deprecations.py +107 -0
  15. openrewrite_migrate_python/migrate/distutils_migrations.py +125 -0
  16. openrewrite_migrate_python/migrate/functools_deprecations.py +98 -0
  17. openrewrite_migrate_python/migrate/gettext_deprecations.py +139 -0
  18. openrewrite_migrate_python/migrate/html_parser_deprecations.py +110 -0
  19. openrewrite_migrate_python/migrate/imp_migrations.py +135 -0
  20. openrewrite_migrate_python/migrate/langchain_classic_imports.py +308 -0
  21. openrewrite_migrate_python/migrate/langchain_community_imports.py +154 -0
  22. openrewrite_migrate_python/migrate/langchain_provider_imports.py +240 -0
  23. openrewrite_migrate_python/migrate/locale_deprecations.py +177 -0
  24. openrewrite_migrate_python/migrate/locale_getdefaultlocale_deprecation.py +103 -0
  25. openrewrite_migrate_python/migrate/macpath_deprecations.py +125 -0
  26. openrewrite_migrate_python/migrate/mailcap_migrations.py +129 -0
  27. openrewrite_migrate_python/migrate/nntplib_migrations.py +127 -0
  28. openrewrite_migrate_python/migrate/os_deprecations.py +158 -0
  29. openrewrite_migrate_python/migrate/pathlib_deprecations.py +98 -0
  30. openrewrite_migrate_python/migrate/pep594_system_migrations.py +429 -0
  31. openrewrite_migrate_python/migrate/pipes_migrations.py +130 -0
  32. openrewrite_migrate_python/migrate/pkgutil_deprecations.py +180 -0
  33. openrewrite_migrate_python/migrate/platform_deprecations.py +99 -0
  34. openrewrite_migrate_python/migrate/re_deprecations.py +122 -0
  35. openrewrite_migrate_python/migrate/removed_modules_312.py +139 -0
  36. openrewrite_migrate_python/migrate/shutil_deprecations.py +112 -0
  37. openrewrite_migrate_python/migrate/socket_deprecations.py +96 -0
  38. openrewrite_migrate_python/migrate/ssl_deprecations.py +121 -0
  39. openrewrite_migrate_python/migrate/string_formatting.py +526 -0
  40. openrewrite_migrate_python/migrate/sys_deprecations.py +97 -0
  41. openrewrite_migrate_python/migrate/sys_last_deprecations.py +104 -0
  42. openrewrite_migrate_python/migrate/tarfile_deprecations.py +120 -0
  43. openrewrite_migrate_python/migrate/telnetlib_migrations.py +132 -0
  44. openrewrite_migrate_python/migrate/tempfile_deprecations.py +113 -0
  45. openrewrite_migrate_python/migrate/threading_deprecations.py +488 -0
  46. openrewrite_migrate_python/migrate/threading_is_alive_deprecation.py +82 -0
  47. openrewrite_migrate_python/migrate/typing_callable.py +153 -0
  48. openrewrite_migrate_python/migrate/typing_deprecations.py +337 -0
  49. openrewrite_migrate_python/migrate/typing_union_to_pipe.py +272 -0
  50. openrewrite_migrate_python/migrate/unittest_deprecations.py +140 -0
  51. openrewrite_migrate_python/migrate/upgrade_to_langchain02.py +56 -0
  52. openrewrite_migrate_python/migrate/upgrade_to_langchain1.py +66 -0
  53. openrewrite_migrate_python/migrate/upgrade_to_python310.py +91 -0
  54. openrewrite_migrate_python/migrate/upgrade_to_python311.py +92 -0
  55. openrewrite_migrate_python/migrate/upgrade_to_python312.py +101 -0
  56. openrewrite_migrate_python/migrate/upgrade_to_python313.py +109 -0
  57. openrewrite_migrate_python/migrate/upgrade_to_python314.py +87 -0
  58. openrewrite_migrate_python/migrate/upgrade_to_python38.py +85 -0
  59. openrewrite_migrate_python/migrate/upgrade_to_python39.py +125 -0
  60. openrewrite_migrate_python/migrate/urllib_deprecations.py +204 -0
  61. openrewrite_migrate_python/migrate/uu_migrations.py +129 -0
  62. openrewrite_migrate_python/migrate/xdrlib_migrations.py +129 -0
  63. openrewrite_migrate_python/migrate/xml_deprecations.py +154 -0
  64. openrewrite_migrate_python-0.1.0.dist-info/METADATA +31 -0
  65. openrewrite_migrate_python-0.1.0.dist-info/RECORD +68 -0
  66. openrewrite_migrate_python-0.1.0.dist-info/WHEEL +5 -0
  67. openrewrite_migrate_python-0.1.0.dist-info/entry_points.txt +2 -0
  68. openrewrite_migrate_python-0.1.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,153 @@
1
+ """
2
+ Recipe for migrating typing.Callable to collections.abc.Callable.
3
+
4
+ PEP 585 (Python 3.9+) deprecated typing.Callable in favor of
5
+ collections.abc.Callable:
6
+
7
+ - typing.Callable[[int], str] -> collections.abc.Callable[[int], str]
8
+
9
+ See: https://peps.python.org/pep-0585/
10
+ """
11
+
12
+ from typing import Any, Optional, Set
13
+
14
+ from rewrite import ExecutionContext, Recipe, TreeVisitor
15
+ from rewrite.category import CategoryDescriptor
16
+ from rewrite.decorators import categorize
17
+ from rewrite.marketplace import Python
18
+ from rewrite.markers import Markers, SearchResult
19
+ from rewrite.utils import random_id
20
+ from rewrite.python.visitor import PythonVisitor
21
+ from rewrite.python.tree import MultiImport
22
+ from rewrite.java.tree import FieldAccess, Identifier, Import
23
+
24
+ # Define category path
25
+ _Python39 = [
26
+ *Python,
27
+ CategoryDescriptor(display_name="Migrate"),
28
+ CategoryDescriptor(display_name="Python 3.9"),
29
+ ]
30
+
31
+
32
+ def _mark_deprecated(tree: Any, message: str, detail: Optional[str] = None) -> Any:
33
+ """Add a SearchResult marker for a deprecation warning."""
34
+ full_message = f"{message}: {detail}" if detail else message
35
+ search_marker = SearchResult(random_id(), full_message)
36
+ current_markers = tree.markers
37
+ new_markers_list = list(current_markers.markers) + [search_marker]
38
+ new_markers = Markers(current_markers.id, new_markers_list)
39
+ return tree.replace(_markers=new_markers)
40
+
41
+
42
+ @categorize(_Python39)
43
+ class ReplaceTypingCallableWithCollectionsAbcCallable(Recipe):
44
+ """
45
+ Find and migrate `typing.Callable` to `collections.abc.Callable`.
46
+
47
+ PEP 585 deprecated `typing.Callable` in Python 3.9. Use
48
+ `collections.abc.Callable` instead for type annotations.
49
+
50
+ Example:
51
+ Before:
52
+ from typing import Callable
53
+ handler: Callable[[int], str] = lambda x: str(x)
54
+
55
+ After:
56
+ from collections.abc import Callable
57
+ handler: Callable[[int], str] = lambda x: str(x)
58
+ """
59
+
60
+ @property
61
+ def name(self) -> str:
62
+ return "org.openrewrite.python.migrate.ReplaceTypingCallableWithCollectionsAbcCallable"
63
+
64
+ @property
65
+ def display_name(self) -> str:
66
+ return "Replace `typing.Callable` with `collections.abc.Callable`"
67
+
68
+ @property
69
+ def description(self) -> str:
70
+ return (
71
+ "PEP 585 deprecated `typing.Callable` in Python 3.9. "
72
+ "Replace with `collections.abc.Callable` for type annotations."
73
+ )
74
+
75
+ def editor(self) -> TreeVisitor[Any, ExecutionContext]:
76
+ class Visitor(PythonVisitor[ExecutionContext]):
77
+ def __init__(self):
78
+ super().__init__()
79
+ self._has_typing_callable_import = False
80
+ self._has_typing_star_import = False
81
+
82
+ def visit_multi_import(self, multi_import: MultiImport, p: ExecutionContext):
83
+ """Track 'from typing import Callable' imports."""
84
+ from_ = multi_import.from_
85
+ if isinstance(from_, Identifier) and from_.simple_name == "typing":
86
+ for imp in multi_import.names:
87
+ qualid = imp.qualid
88
+ if isinstance(qualid, FieldAccess):
89
+ name = qualid.name
90
+ if isinstance(name, Identifier) and name.simple_name == "Callable":
91
+ self._has_typing_callable_import = True
92
+ elif isinstance(qualid, Identifier) and qualid.simple_name == "Callable":
93
+ self._has_typing_callable_import = True
94
+ return super().visit_multi_import(multi_import, p)
95
+
96
+ def visit_import(self, import_node: Import, p: ExecutionContext):
97
+ """Track 'import typing' imports."""
98
+ qualid = import_node.qualid
99
+ if isinstance(qualid, Identifier) and qualid.simple_name == "typing":
100
+ self._has_typing_star_import = True
101
+ elif isinstance(qualid, FieldAccess):
102
+ name = qualid.name
103
+ if isinstance(name, Identifier) and name.simple_name == "typing":
104
+ self._has_typing_star_import = True
105
+ return super().visit_import(import_node, p)
106
+
107
+ def visit_identifier(
108
+ self, identifier: Identifier, p: ExecutionContext
109
+ ) -> Optional[Identifier]:
110
+ identifier = super().visit_identifier(identifier, p)
111
+
112
+ if identifier.simple_name == "Callable" and self._has_typing_callable_import:
113
+ # Skip identifiers that are part of import statements
114
+ if not self._is_in_import(identifier):
115
+ return _mark_deprecated(
116
+ identifier,
117
+ "typing.Callable is deprecated",
118
+ "Replace with collections.abc.Callable (PEP 585)"
119
+ )
120
+
121
+ return identifier
122
+
123
+ def visit_field_access(self, field_access: FieldAccess, p: ExecutionContext):
124
+ """Handle typing.Callable qualified access."""
125
+ field_access = super().visit_field_access(field_access, p)
126
+
127
+ if self._has_typing_star_import:
128
+ name = field_access.name
129
+ target = field_access.target
130
+ if (isinstance(name, Identifier) and name.simple_name == "Callable" and
131
+ isinstance(target, Identifier) and target.simple_name == "typing"):
132
+ marked_name = _mark_deprecated(
133
+ name,
134
+ "typing.Callable is deprecated",
135
+ "Replace with collections.abc.Callable (PEP 585)"
136
+ )
137
+ return field_access.replace(
138
+ _name=field_access.padding.name.replace(_element=marked_name)
139
+ )
140
+
141
+ return field_access
142
+
143
+ def _is_in_import(self, identifier: Identifier) -> bool:
144
+ """Check if the identifier is inside an import statement."""
145
+ cursor = self.cursor
146
+ while cursor is not None:
147
+ value = cursor.value
148
+ if isinstance(value, (Import, MultiImport)):
149
+ return True
150
+ cursor = cursor.parent
151
+ return False
152
+
153
+ return Visitor()
@@ -0,0 +1,337 @@
1
+ """
2
+ Recipes for migrating deprecated typing module aliases to built-in generics.
3
+
4
+ PEP 585 (Python 3.9+) deprecated many typing module aliases in favor of
5
+ using built-in types directly as generics:
6
+
7
+ - typing.List[X] -> list[X]
8
+ - typing.Dict[K, V] -> dict[K, V]
9
+ - typing.Set[X] -> set[X]
10
+ - typing.FrozenSet[X] -> frozenset[X]
11
+ - typing.Tuple[X, ...] -> tuple[X, ...]
12
+ - typing.Type[X] -> type[X]
13
+
14
+ Additionally, typing.Text is deprecated (alias for str since Python 3.11).
15
+
16
+ See: https://peps.python.org/pep-0585/
17
+ """
18
+
19
+ from typing import Any, Optional, Dict
20
+
21
+ from rewrite import ExecutionContext, Recipe, TreeVisitor
22
+ from rewrite.category import CategoryDescriptor
23
+ from rewrite.decorators import categorize
24
+ from rewrite.marketplace import Python
25
+ from rewrite.markers import Markers, SearchResult
26
+ from rewrite.utils import random_id
27
+ from rewrite.python.visitor import PythonVisitor
28
+ from rewrite.java.tree import Identifier
29
+
30
+ # Define category paths
31
+ _Python39 = [
32
+ *Python,
33
+ CategoryDescriptor(display_name="Migrate"),
34
+ CategoryDescriptor(display_name="Python 3.9"),
35
+ ]
36
+
37
+ _Python311 = [
38
+ *Python,
39
+ CategoryDescriptor(display_name="Migrate"),
40
+ CategoryDescriptor(display_name="Python 3.11"),
41
+ ]
42
+
43
+
44
+ def _mark_deprecated(tree: Any, message: str, detail: Optional[str] = None) -> Any:
45
+ """Add a SearchResult marker for a deprecation warning."""
46
+ full_message = f"{message}: {detail}" if detail else message
47
+ search_marker = SearchResult(random_id(), full_message)
48
+ current_markers = tree.markers
49
+ new_markers_list = list(current_markers.markers) + [search_marker]
50
+ new_markers = Markers(current_markers.id, new_markers_list)
51
+ return tree.replace(_markers=new_markers)
52
+
53
+
54
+ # PEP 585 deprecated typing aliases -> built-in replacements
55
+ PEP585_DEPRECATIONS: Dict[str, str] = {
56
+ "List": "list",
57
+ "Dict": "dict",
58
+ "Set": "set",
59
+ "FrozenSet": "frozenset",
60
+ "Tuple": "tuple",
61
+ "Type": "type",
62
+ }
63
+
64
+
65
+ @categorize(_Python39)
66
+ class ReplaceTypingListWithList(Recipe):
67
+ """
68
+ Find and migrate `typing.List` to built-in `list`.
69
+
70
+ PEP 585 deprecated `typing.List` in Python 3.9. The built-in `list` type
71
+ can now be used directly as a generic type.
72
+
73
+ Example:
74
+ Before:
75
+ from typing import List
76
+ items: List[str] = []
77
+
78
+ After:
79
+ items: list[str] = []
80
+ """
81
+
82
+ @property
83
+ def name(self) -> str:
84
+ return "org.openrewrite.python.migrate.ReplaceTypingListWithList"
85
+
86
+ @property
87
+ def display_name(self) -> str:
88
+ return "Replace `typing.List` with `list`"
89
+
90
+ @property
91
+ def description(self) -> str:
92
+ return (
93
+ "PEP 585 deprecated `typing.List` in Python 3.9. "
94
+ "Replace with the built-in `list` type for generic annotations."
95
+ )
96
+
97
+ def editor(self) -> TreeVisitor[Any, ExecutionContext]:
98
+ class Visitor(PythonVisitor[ExecutionContext]):
99
+ def visit_identifier(
100
+ self, identifier: Identifier, p: ExecutionContext
101
+ ) -> Optional[Identifier]:
102
+ identifier = super().visit_identifier(identifier, p)
103
+
104
+ if identifier.simple_name == "List":
105
+ # Check if this is from typing module via type attribution
106
+ if identifier.field_type:
107
+ fqn = str(getattr(identifier.field_type, '_fully_qualified_name', ''))
108
+ if 'typing' in fqn:
109
+ return _mark_deprecated(
110
+ identifier,
111
+ "typing.List is deprecated",
112
+ "Replace with built-in list (PEP 585)"
113
+ )
114
+
115
+ return identifier
116
+
117
+ return Visitor()
118
+
119
+
120
+ @categorize(_Python39)
121
+ class ReplaceTypingDictWithDict(Recipe):
122
+ """
123
+ Find and migrate `typing.Dict` to built-in `dict`.
124
+
125
+ PEP 585 deprecated `typing.Dict` in Python 3.9. The built-in `dict` type
126
+ can now be used directly as a generic type.
127
+
128
+ Example:
129
+ Before:
130
+ from typing import Dict
131
+ mapping: Dict[str, int] = {}
132
+
133
+ After:
134
+ mapping: dict[str, int] = {}
135
+ """
136
+
137
+ @property
138
+ def name(self) -> str:
139
+ return "org.openrewrite.python.migrate.ReplaceTypingDictWithDict"
140
+
141
+ @property
142
+ def display_name(self) -> str:
143
+ return "Replace `typing.Dict` with `dict`"
144
+
145
+ @property
146
+ def description(self) -> str:
147
+ return (
148
+ "PEP 585 deprecated `typing.Dict` in Python 3.9. "
149
+ "Replace with the built-in `dict` type for generic annotations."
150
+ )
151
+
152
+ def editor(self) -> TreeVisitor[Any, ExecutionContext]:
153
+ class Visitor(PythonVisitor[ExecutionContext]):
154
+ def visit_identifier(
155
+ self, identifier: Identifier, p: ExecutionContext
156
+ ) -> Optional[Identifier]:
157
+ identifier = super().visit_identifier(identifier, p)
158
+
159
+ if identifier.simple_name == "Dict":
160
+ if identifier.field_type:
161
+ fqn = str(getattr(identifier.field_type, '_fully_qualified_name', ''))
162
+ if 'typing' in fqn:
163
+ return _mark_deprecated(
164
+ identifier,
165
+ "typing.Dict is deprecated",
166
+ "Replace with built-in dict (PEP 585)"
167
+ )
168
+
169
+ return identifier
170
+
171
+ return Visitor()
172
+
173
+
174
+ @categorize(_Python39)
175
+ class ReplaceTypingSetWithSet(Recipe):
176
+ """
177
+ Find and migrate `typing.Set` to built-in `set`.
178
+
179
+ PEP 585 deprecated `typing.Set` in Python 3.9. The built-in `set` type
180
+ can now be used directly as a generic type.
181
+
182
+ Example:
183
+ Before:
184
+ from typing import Set
185
+ items: Set[int] = set()
186
+
187
+ After:
188
+ items: set[int] = set()
189
+ """
190
+
191
+ @property
192
+ def name(self) -> str:
193
+ return "org.openrewrite.python.migrate.ReplaceTypingSetWithSet"
194
+
195
+ @property
196
+ def display_name(self) -> str:
197
+ return "Replace `typing.Set` with `set`"
198
+
199
+ @property
200
+ def description(self) -> str:
201
+ return (
202
+ "PEP 585 deprecated `typing.Set` in Python 3.9. "
203
+ "Replace with the built-in `set` type for generic annotations."
204
+ )
205
+
206
+ def editor(self) -> TreeVisitor[Any, ExecutionContext]:
207
+ class Visitor(PythonVisitor[ExecutionContext]):
208
+ def visit_identifier(
209
+ self, identifier: Identifier, p: ExecutionContext
210
+ ) -> Optional[Identifier]:
211
+ identifier = super().visit_identifier(identifier, p)
212
+
213
+ if identifier.simple_name == "Set":
214
+ if identifier.field_type:
215
+ fqn = str(getattr(identifier.field_type, '_fully_qualified_name', ''))
216
+ if 'typing' in fqn:
217
+ return _mark_deprecated(
218
+ identifier,
219
+ "typing.Set is deprecated",
220
+ "Replace with built-in set (PEP 585)"
221
+ )
222
+
223
+ return identifier
224
+
225
+ return Visitor()
226
+
227
+
228
+ @categorize(_Python39)
229
+ class ReplaceTypingTupleWithTuple(Recipe):
230
+ """
231
+ Find and migrate `typing.Tuple` to built-in `tuple`.
232
+
233
+ PEP 585 deprecated `typing.Tuple` in Python 3.9. The built-in `tuple` type
234
+ can now be used directly as a generic type.
235
+
236
+ Example:
237
+ Before:
238
+ from typing import Tuple
239
+ point: Tuple[int, int] = (0, 0)
240
+
241
+ After:
242
+ point: tuple[int, int] = (0, 0)
243
+ """
244
+
245
+ @property
246
+ def name(self) -> str:
247
+ return "org.openrewrite.python.migrate.ReplaceTypingTupleWithTuple"
248
+
249
+ @property
250
+ def display_name(self) -> str:
251
+ return "Replace `typing.Tuple` with `tuple`"
252
+
253
+ @property
254
+ def description(self) -> str:
255
+ return (
256
+ "PEP 585 deprecated `typing.Tuple` in Python 3.9. "
257
+ "Replace with the built-in `tuple` type for generic annotations."
258
+ )
259
+
260
+ def editor(self) -> TreeVisitor[Any, ExecutionContext]:
261
+ class Visitor(PythonVisitor[ExecutionContext]):
262
+ def visit_identifier(
263
+ self, identifier: Identifier, p: ExecutionContext
264
+ ) -> Optional[Identifier]:
265
+ identifier = super().visit_identifier(identifier, p)
266
+
267
+ if identifier.simple_name == "Tuple":
268
+ if identifier.field_type:
269
+ fqn = str(getattr(identifier.field_type, '_fully_qualified_name', ''))
270
+ if 'typing' in fqn:
271
+ return _mark_deprecated(
272
+ identifier,
273
+ "typing.Tuple is deprecated",
274
+ "Replace with built-in tuple (PEP 585)"
275
+ )
276
+
277
+ return identifier
278
+
279
+ return Visitor()
280
+
281
+
282
+ @categorize(_Python311)
283
+ class ReplaceTypingText(Recipe):
284
+ """
285
+ Find and migrate `typing.Text` to `str`.
286
+
287
+ `typing.Text` was an alias for `str` provided for Python 2/3 compatibility.
288
+ It is deprecated as of Python 3.11 since Python 2 is no longer supported.
289
+
290
+ Example:
291
+ Before:
292
+ from typing import Text
293
+ name: Text = "hello"
294
+
295
+ After:
296
+ name: str = "hello"
297
+ """
298
+
299
+ @property
300
+ def name(self) -> str:
301
+ return "org.openrewrite.python.migrate.ReplaceTypingText"
302
+
303
+ @property
304
+ def display_name(self) -> str:
305
+ return "Replace `typing.Text` with `str`"
306
+
307
+ @property
308
+ def description(self) -> str:
309
+ return (
310
+ "`typing.Text` is deprecated as of Python 3.11. "
311
+ "It was an alias for `str` for Python 2/3 compatibility. Replace with `str`."
312
+ )
313
+
314
+ def editor(self) -> TreeVisitor[Any, ExecutionContext]:
315
+ from rewrite.python.tree import Import, MultiImport
316
+
317
+ class Visitor(PythonVisitor[ExecutionContext]):
318
+ def visit_identifier(
319
+ self, ident: Identifier, p: ExecutionContext
320
+ ) -> Optional[Identifier]:
321
+ ident = super().visit_identifier(ident, p)
322
+
323
+ if ident.simple_name != "Text":
324
+ return ident
325
+
326
+ # Skip identifiers inside import statements
327
+ if (self.cursor.first_enclosing(MultiImport) is not None or
328
+ self.cursor.first_enclosing(Import) is not None):
329
+ return ident
330
+
331
+ # Type attribution correctly resolves typing.Text to str
332
+ # (since Text is just an alias), so we can't use field_type to
333
+ # confirm the import origin. Instead we rely on the name check
334
+ # and the import-context guard above.
335
+ return ident.replace(_simple_name="str")
336
+
337
+ return Visitor()