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.
- openrewrite_migrate_python/__init__.py +35 -0
- openrewrite_migrate_python/migrate/__init__.py +219 -0
- openrewrite_migrate_python/migrate/aifc_migrations.py +517 -0
- openrewrite_migrate_python/migrate/array_deprecations.py +133 -0
- openrewrite_migrate_python/migrate/ast_deprecations.py +322 -0
- openrewrite_migrate_python/migrate/asyncio_coroutine_to_async.py +225 -0
- openrewrite_migrate_python/migrate/asyncio_deprecations.py +117 -0
- openrewrite_migrate_python/migrate/calendar_deprecations.py +134 -0
- openrewrite_migrate_python/migrate/cgi_migrations.py +213 -0
- openrewrite_migrate_python/migrate/cgi_parse_deprecations.py +170 -0
- openrewrite_migrate_python/migrate/collections_abc_migrations.py +207 -0
- openrewrite_migrate_python/migrate/configparser_deprecations.py +252 -0
- openrewrite_migrate_python/migrate/datetime_utc.py +136 -0
- openrewrite_migrate_python/migrate/distutils_deprecations.py +107 -0
- openrewrite_migrate_python/migrate/distutils_migrations.py +125 -0
- openrewrite_migrate_python/migrate/functools_deprecations.py +98 -0
- openrewrite_migrate_python/migrate/gettext_deprecations.py +139 -0
- openrewrite_migrate_python/migrate/html_parser_deprecations.py +110 -0
- openrewrite_migrate_python/migrate/imp_migrations.py +135 -0
- openrewrite_migrate_python/migrate/langchain_classic_imports.py +308 -0
- openrewrite_migrate_python/migrate/langchain_community_imports.py +154 -0
- openrewrite_migrate_python/migrate/langchain_provider_imports.py +240 -0
- openrewrite_migrate_python/migrate/locale_deprecations.py +177 -0
- openrewrite_migrate_python/migrate/locale_getdefaultlocale_deprecation.py +103 -0
- openrewrite_migrate_python/migrate/macpath_deprecations.py +125 -0
- openrewrite_migrate_python/migrate/mailcap_migrations.py +129 -0
- openrewrite_migrate_python/migrate/nntplib_migrations.py +127 -0
- openrewrite_migrate_python/migrate/os_deprecations.py +158 -0
- openrewrite_migrate_python/migrate/pathlib_deprecations.py +98 -0
- openrewrite_migrate_python/migrate/pep594_system_migrations.py +429 -0
- openrewrite_migrate_python/migrate/pipes_migrations.py +130 -0
- openrewrite_migrate_python/migrate/pkgutil_deprecations.py +180 -0
- openrewrite_migrate_python/migrate/platform_deprecations.py +99 -0
- openrewrite_migrate_python/migrate/re_deprecations.py +122 -0
- openrewrite_migrate_python/migrate/removed_modules_312.py +139 -0
- openrewrite_migrate_python/migrate/shutil_deprecations.py +112 -0
- openrewrite_migrate_python/migrate/socket_deprecations.py +96 -0
- openrewrite_migrate_python/migrate/ssl_deprecations.py +121 -0
- openrewrite_migrate_python/migrate/string_formatting.py +526 -0
- openrewrite_migrate_python/migrate/sys_deprecations.py +97 -0
- openrewrite_migrate_python/migrate/sys_last_deprecations.py +104 -0
- openrewrite_migrate_python/migrate/tarfile_deprecations.py +120 -0
- openrewrite_migrate_python/migrate/telnetlib_migrations.py +132 -0
- openrewrite_migrate_python/migrate/tempfile_deprecations.py +113 -0
- openrewrite_migrate_python/migrate/threading_deprecations.py +488 -0
- openrewrite_migrate_python/migrate/threading_is_alive_deprecation.py +82 -0
- openrewrite_migrate_python/migrate/typing_callable.py +153 -0
- openrewrite_migrate_python/migrate/typing_deprecations.py +337 -0
- openrewrite_migrate_python/migrate/typing_union_to_pipe.py +272 -0
- openrewrite_migrate_python/migrate/unittest_deprecations.py +140 -0
- openrewrite_migrate_python/migrate/upgrade_to_langchain02.py +56 -0
- openrewrite_migrate_python/migrate/upgrade_to_langchain1.py +66 -0
- openrewrite_migrate_python/migrate/upgrade_to_python310.py +91 -0
- openrewrite_migrate_python/migrate/upgrade_to_python311.py +92 -0
- openrewrite_migrate_python/migrate/upgrade_to_python312.py +101 -0
- openrewrite_migrate_python/migrate/upgrade_to_python313.py +109 -0
- openrewrite_migrate_python/migrate/upgrade_to_python314.py +87 -0
- openrewrite_migrate_python/migrate/upgrade_to_python38.py +85 -0
- openrewrite_migrate_python/migrate/upgrade_to_python39.py +125 -0
- openrewrite_migrate_python/migrate/urllib_deprecations.py +204 -0
- openrewrite_migrate_python/migrate/uu_migrations.py +129 -0
- openrewrite_migrate_python/migrate/xdrlib_migrations.py +129 -0
- openrewrite_migrate_python/migrate/xml_deprecations.py +154 -0
- openrewrite_migrate_python-0.1.0.dist-info/METADATA +31 -0
- openrewrite_migrate_python-0.1.0.dist-info/RECORD +68 -0
- openrewrite_migrate_python-0.1.0.dist-info/WHEEL +5 -0
- openrewrite_migrate_python-0.1.0.dist-info/entry_points.txt +2 -0
- openrewrite_migrate_python-0.1.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,272 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Recipes for migrating typing.Optional and typing.Union to PEP 604 union syntax.
|
|
3
|
+
|
|
4
|
+
PEP 604 (Python 3.10+) introduced the `X | Y` syntax for union types:
|
|
5
|
+
|
|
6
|
+
- typing.Optional[X] -> X | None
|
|
7
|
+
- typing.Union[X, Y] -> X | Y
|
|
8
|
+
- typing.Union[X, Y, Z] -> X | Y | Z
|
|
9
|
+
|
|
10
|
+
See: https://peps.python.org/pep-0604/
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
from typing import Any, List, Optional
|
|
14
|
+
|
|
15
|
+
from rewrite import ExecutionContext, Recipe, TreeVisitor
|
|
16
|
+
from rewrite.category import CategoryDescriptor
|
|
17
|
+
from rewrite.decorators import categorize
|
|
18
|
+
from rewrite.marketplace import Python
|
|
19
|
+
from rewrite.markers import Markers
|
|
20
|
+
from rewrite.python.visitor import PythonVisitor
|
|
21
|
+
from rewrite.java.support_types import JRightPadded, Space
|
|
22
|
+
from rewrite.java.tree import (
|
|
23
|
+
ArrayAccess,
|
|
24
|
+
Expression,
|
|
25
|
+
FieldAccess,
|
|
26
|
+
Identifier,
|
|
27
|
+
Literal,
|
|
28
|
+
ParameterizedType,
|
|
29
|
+
)
|
|
30
|
+
from rewrite.python.tree import CollectionLiteral, UnionType
|
|
31
|
+
from rewrite.utils import random_id
|
|
32
|
+
|
|
33
|
+
# Define category path: Python > Migrate > Python 3.10
|
|
34
|
+
_Python310 = [
|
|
35
|
+
*Python,
|
|
36
|
+
CategoryDescriptor(display_name="Migrate"),
|
|
37
|
+
CategoryDescriptor(display_name="Python 3.10"),
|
|
38
|
+
]
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def _is_typing_optional(clazz: Expression) -> bool:
|
|
42
|
+
"""Check if a clazz expression is typing.Optional or just Optional."""
|
|
43
|
+
if isinstance(clazz, Identifier):
|
|
44
|
+
return clazz.simple_name == "Optional"
|
|
45
|
+
if isinstance(clazz, FieldAccess):
|
|
46
|
+
name = clazz.name
|
|
47
|
+
target = clazz.target
|
|
48
|
+
if (isinstance(name, Identifier) and name.simple_name == "Optional" and
|
|
49
|
+
isinstance(target, Identifier) and target.simple_name == "typing"):
|
|
50
|
+
return True
|
|
51
|
+
return False
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def _is_typing_union(clazz: Expression) -> bool:
|
|
55
|
+
"""Check if a clazz expression is typing.Union or just Union."""
|
|
56
|
+
if isinstance(clazz, Identifier):
|
|
57
|
+
return clazz.simple_name == "Union"
|
|
58
|
+
if isinstance(clazz, FieldAccess):
|
|
59
|
+
name = clazz.name
|
|
60
|
+
target = clazz.target
|
|
61
|
+
if (isinstance(name, Identifier) and name.simple_name == "Union" and
|
|
62
|
+
isinstance(target, Identifier) and target.simple_name == "typing"):
|
|
63
|
+
return True
|
|
64
|
+
return False
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def _create_none_literal(prefix: Space) -> Literal:
|
|
68
|
+
"""Create a Literal node representing None."""
|
|
69
|
+
return Literal(
|
|
70
|
+
_id=random_id(),
|
|
71
|
+
_prefix=prefix,
|
|
72
|
+
_markers=Markers.EMPTY,
|
|
73
|
+
_value=None,
|
|
74
|
+
_value_source="None",
|
|
75
|
+
_unicode_escapes=None,
|
|
76
|
+
_type=None,
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def _create_union_type(types: List[Expression], prefix: Space) -> UnionType:
|
|
81
|
+
"""Create a UnionType node (X | Y | Z).
|
|
82
|
+
|
|
83
|
+
The UnionType node represents the PEP 604 union syntax.
|
|
84
|
+
Each type in the list is separated by ' | '.
|
|
85
|
+
"""
|
|
86
|
+
# Create JRightPadded list with ' | ' after each type except the last
|
|
87
|
+
padded_types = []
|
|
88
|
+
for i, type_expr in enumerate(types):
|
|
89
|
+
# First type keeps its own prefix (or empty)
|
|
90
|
+
if i == 0:
|
|
91
|
+
type_expr = type_expr.replace(_prefix=Space.EMPTY) if hasattr(type_expr, 'replace') else type_expr
|
|
92
|
+
else:
|
|
93
|
+
# Other types get single space prefix (after the |)
|
|
94
|
+
type_expr = type_expr.replace(_prefix=Space.SINGLE_SPACE) if hasattr(type_expr, 'replace') else type_expr
|
|
95
|
+
|
|
96
|
+
# All types except the last get ' | ' after (space before |)
|
|
97
|
+
if i < len(types) - 1:
|
|
98
|
+
after = Space.SINGLE_SPACE # Space before the |
|
|
99
|
+
else:
|
|
100
|
+
after = Space.EMPTY
|
|
101
|
+
|
|
102
|
+
padded_types.append(JRightPadded(
|
|
103
|
+
_element=type_expr,
|
|
104
|
+
_after=after,
|
|
105
|
+
_markers=Markers.EMPTY,
|
|
106
|
+
))
|
|
107
|
+
|
|
108
|
+
return UnionType(
|
|
109
|
+
_id=random_id(),
|
|
110
|
+
_prefix=prefix,
|
|
111
|
+
_markers=Markers.EMPTY,
|
|
112
|
+
_types=padded_types,
|
|
113
|
+
_type=None,
|
|
114
|
+
)
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
@categorize(_Python310)
|
|
118
|
+
class ReplaceTypingOptionalWithUnion(Recipe):
|
|
119
|
+
"""
|
|
120
|
+
Replace `typing.Optional[X]` with `X | None` (PEP 604).
|
|
121
|
+
|
|
122
|
+
PEP 604 introduced the `|` operator for union types in Python 3.10.
|
|
123
|
+
`Optional[X]` is equivalent to `X | None`.
|
|
124
|
+
|
|
125
|
+
Example:
|
|
126
|
+
Before:
|
|
127
|
+
from typing import Optional
|
|
128
|
+
name: Optional[str] = None
|
|
129
|
+
|
|
130
|
+
After:
|
|
131
|
+
name: str | None = None
|
|
132
|
+
"""
|
|
133
|
+
|
|
134
|
+
@property
|
|
135
|
+
def name(self) -> str:
|
|
136
|
+
return "org.openrewrite.python.migrate.ReplaceTypingOptionalWithUnion"
|
|
137
|
+
|
|
138
|
+
@property
|
|
139
|
+
def display_name(self) -> str:
|
|
140
|
+
return "Replace `typing.Optional[X]` with `X | None`"
|
|
141
|
+
|
|
142
|
+
@property
|
|
143
|
+
def description(self) -> str:
|
|
144
|
+
return (
|
|
145
|
+
"PEP 604 introduced the `|` operator for union types in Python 3.10. "
|
|
146
|
+
"Replace `Optional[X]` with the more concise `X | None` syntax."
|
|
147
|
+
)
|
|
148
|
+
|
|
149
|
+
@property
|
|
150
|
+
def tags(self) -> List[str]:
|
|
151
|
+
return ["python", "migration", "3.10", "typing", "pep604"]
|
|
152
|
+
|
|
153
|
+
def editor(self) -> TreeVisitor[Any, ExecutionContext]:
|
|
154
|
+
class Visitor(PythonVisitor[ExecutionContext]):
|
|
155
|
+
def visit_parameterized_type(
|
|
156
|
+
self, param_type: ParameterizedType, p: ExecutionContext
|
|
157
|
+
) -> Optional[Expression]:
|
|
158
|
+
param_type = super().visit_parameterized_type(param_type, p)
|
|
159
|
+
|
|
160
|
+
# Check if this is Optional[X]
|
|
161
|
+
if not _is_typing_optional(param_type.clazz):
|
|
162
|
+
return param_type
|
|
163
|
+
|
|
164
|
+
# Get the type arguments
|
|
165
|
+
type_params = param_type.type_parameters
|
|
166
|
+
if type_params is None or len(type_params) != 1:
|
|
167
|
+
return param_type
|
|
168
|
+
|
|
169
|
+
type_arg = type_params[0]
|
|
170
|
+
|
|
171
|
+
# Create X | None using UnionType
|
|
172
|
+
none_literal = _create_none_literal(Space.EMPTY)
|
|
173
|
+
return _create_union_type([type_arg, none_literal], param_type.prefix)
|
|
174
|
+
|
|
175
|
+
def visit_array_access(
|
|
176
|
+
self, array_access: ArrayAccess, p: ExecutionContext
|
|
177
|
+
) -> Optional[Expression]:
|
|
178
|
+
array_access = super().visit_array_access(array_access, p)
|
|
179
|
+
|
|
180
|
+
# Check if this is Optional[X]
|
|
181
|
+
if not _is_typing_optional(array_access.indexed):
|
|
182
|
+
return array_access
|
|
183
|
+
|
|
184
|
+
# Get the type argument from the dimension
|
|
185
|
+
index = array_access.dimension.index
|
|
186
|
+
|
|
187
|
+
# Create X | None using UnionType
|
|
188
|
+
none_literal = _create_none_literal(Space.EMPTY)
|
|
189
|
+
return _create_union_type([index, none_literal], array_access.prefix)
|
|
190
|
+
|
|
191
|
+
return Visitor()
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
@categorize(_Python310)
|
|
195
|
+
class ReplaceTypingUnionWithPipe(Recipe):
|
|
196
|
+
"""
|
|
197
|
+
Replace `typing.Union[X, Y]` with `X | Y` (PEP 604).
|
|
198
|
+
|
|
199
|
+
PEP 604 introduced the `|` operator for union types in Python 3.10.
|
|
200
|
+
`Union[X, Y, Z]` becomes `X | Y | Z`.
|
|
201
|
+
|
|
202
|
+
Example:
|
|
203
|
+
Before:
|
|
204
|
+
from typing import Union
|
|
205
|
+
value: Union[int, str] = 0
|
|
206
|
+
|
|
207
|
+
After:
|
|
208
|
+
value: int | str = 0
|
|
209
|
+
"""
|
|
210
|
+
|
|
211
|
+
@property
|
|
212
|
+
def name(self) -> str:
|
|
213
|
+
return "org.openrewrite.python.migrate.ReplaceTypingUnionWithPipe"
|
|
214
|
+
|
|
215
|
+
@property
|
|
216
|
+
def display_name(self) -> str:
|
|
217
|
+
return "Replace `typing.Union[X, Y]` with `X | Y`"
|
|
218
|
+
|
|
219
|
+
@property
|
|
220
|
+
def description(self) -> str:
|
|
221
|
+
return (
|
|
222
|
+
"PEP 604 introduced the `|` operator for union types in Python 3.10. "
|
|
223
|
+
"Replace `Union[X, Y, ...]` with the more concise `X | Y | ...` syntax."
|
|
224
|
+
)
|
|
225
|
+
|
|
226
|
+
@property
|
|
227
|
+
def tags(self) -> List[str]:
|
|
228
|
+
return ["python", "migration", "3.10", "typing", "pep604"]
|
|
229
|
+
|
|
230
|
+
def editor(self) -> TreeVisitor[Any, ExecutionContext]:
|
|
231
|
+
class Visitor(PythonVisitor[ExecutionContext]):
|
|
232
|
+
def visit_parameterized_type(
|
|
233
|
+
self, param_type: ParameterizedType, p: ExecutionContext
|
|
234
|
+
) -> Optional[Expression]:
|
|
235
|
+
param_type = super().visit_parameterized_type(param_type, p)
|
|
236
|
+
|
|
237
|
+
# Check if this is Union[X, Y, ...]
|
|
238
|
+
if not _is_typing_union(param_type.clazz):
|
|
239
|
+
return param_type
|
|
240
|
+
|
|
241
|
+
# Get the type arguments
|
|
242
|
+
type_params = param_type.type_parameters
|
|
243
|
+
if type_params is None or len(type_params) < 2:
|
|
244
|
+
return param_type
|
|
245
|
+
|
|
246
|
+
# Create union type with all type parameters
|
|
247
|
+
return _create_union_type(list(type_params), param_type.prefix)
|
|
248
|
+
|
|
249
|
+
def visit_array_access(
|
|
250
|
+
self, array_access: ArrayAccess, p: ExecutionContext
|
|
251
|
+
) -> Optional[Expression]:
|
|
252
|
+
array_access = super().visit_array_access(array_access, p)
|
|
253
|
+
|
|
254
|
+
# Check if this is Union[X, Y, ...]
|
|
255
|
+
if not _is_typing_union(array_access.indexed):
|
|
256
|
+
return array_access
|
|
257
|
+
|
|
258
|
+
# Get the type arguments from the dimension
|
|
259
|
+
index = array_access.dimension.index
|
|
260
|
+
|
|
261
|
+
# Extract elements from CollectionLiteral
|
|
262
|
+
if not isinstance(index, CollectionLiteral):
|
|
263
|
+
return array_access
|
|
264
|
+
|
|
265
|
+
elements = list(index.elements)
|
|
266
|
+
if len(elements) < 2:
|
|
267
|
+
return array_access
|
|
268
|
+
|
|
269
|
+
# Create union type with all elements
|
|
270
|
+
return _create_union_type(elements, array_access.prefix)
|
|
271
|
+
|
|
272
|
+
return Visitor()
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Recipes for migrating deprecated unittest method aliases.
|
|
3
|
+
|
|
4
|
+
Several unittest.TestCase method aliases were deprecated in Python 3.1-3.2
|
|
5
|
+
and removed in Python 3.11/3.12:
|
|
6
|
+
|
|
7
|
+
- assertEquals → assertEqual
|
|
8
|
+
- assertNotEquals → assertNotEqual
|
|
9
|
+
- assertAlmostEquals → assertAlmostEqual
|
|
10
|
+
- assertNotAlmostEquals → assertNotAlmostEqual
|
|
11
|
+
- assertRegexpMatches → assertRegex (deprecated 3.2, removed 3.12)
|
|
12
|
+
- assertNotRegexpMatches → assertNotRegex (deprecated 3.2, removed 3.12)
|
|
13
|
+
- assertRaisesRegexp → assertRaisesRegex (deprecated 3.2, removed 3.12)
|
|
14
|
+
|
|
15
|
+
See: https://docs.python.org/3/library/unittest.html
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
from typing import Any, Optional, Dict
|
|
19
|
+
|
|
20
|
+
from rewrite import ExecutionContext, Recipe, TreeVisitor
|
|
21
|
+
from rewrite.category import CategoryDescriptor
|
|
22
|
+
from rewrite.decorators import categorize
|
|
23
|
+
from rewrite.marketplace import Python
|
|
24
|
+
from rewrite.python.visitor import PythonVisitor
|
|
25
|
+
from rewrite.java.tree import Identifier, MethodInvocation
|
|
26
|
+
|
|
27
|
+
# Define category path: Python > Migrate > Python 3.11
|
|
28
|
+
_Python311 = [
|
|
29
|
+
*Python,
|
|
30
|
+
CategoryDescriptor(display_name="Migrate"),
|
|
31
|
+
CategoryDescriptor(display_name="Python 3.11"),
|
|
32
|
+
]
|
|
33
|
+
|
|
34
|
+
# Mapping of deprecated method names to their replacements
|
|
35
|
+
UNITTEST_ALIASES: Dict[str, str] = {
|
|
36
|
+
# Deprecated in 3.1, removed in 3.11
|
|
37
|
+
"assertEquals": "assertEqual",
|
|
38
|
+
"assertNotEquals": "assertNotEqual",
|
|
39
|
+
"assertAlmostEquals": "assertAlmostEqual",
|
|
40
|
+
"assertNotAlmostEquals": "assertNotAlmostEqual",
|
|
41
|
+
# Deprecated in 3.2, removed in 3.12
|
|
42
|
+
"assertRegexpMatches": "assertRegex",
|
|
43
|
+
"assertNotRegexpMatches": "assertNotRegex",
|
|
44
|
+
"assertRaisesRegexp": "assertRaisesRegex",
|
|
45
|
+
# Very old aliases (deprecated since 3.1)
|
|
46
|
+
"failUnlessEqual": "assertEqual",
|
|
47
|
+
"failIfEqual": "assertNotEqual",
|
|
48
|
+
"failUnless": "assertTrue",
|
|
49
|
+
"failIf": "assertFalse",
|
|
50
|
+
"failUnlessRaises": "assertRaises",
|
|
51
|
+
"failUnlessAlmostEqual": "assertAlmostEqual",
|
|
52
|
+
"failIfAlmostEqual": "assertNotAlmostEqual",
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def _rename_method(method: MethodInvocation, new_name: str) -> MethodInvocation:
|
|
57
|
+
"""Rename a method invocation."""
|
|
58
|
+
old_name = method.name
|
|
59
|
+
if not isinstance(old_name, Identifier):
|
|
60
|
+
return method
|
|
61
|
+
|
|
62
|
+
new_identifier = old_name.replace(_simple_name=new_name)
|
|
63
|
+
return method.replace(_name=new_identifier)
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def _is_self_method(method: MethodInvocation) -> bool:
|
|
67
|
+
"""Check if this is a method call on self (typical for unittest)."""
|
|
68
|
+
select = method.select
|
|
69
|
+
if select is None:
|
|
70
|
+
return False
|
|
71
|
+
if isinstance(select, Identifier) and select.simple_name == "self":
|
|
72
|
+
return True
|
|
73
|
+
return False
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
@categorize(_Python311)
|
|
77
|
+
class ReplaceUnittestDeprecatedAliases(Recipe):
|
|
78
|
+
"""
|
|
79
|
+
Replace deprecated unittest.TestCase method aliases with their modern equivalents.
|
|
80
|
+
|
|
81
|
+
Several unittest method aliases were deprecated and later removed:
|
|
82
|
+
- assertEquals → assertEqual
|
|
83
|
+
- assertNotEquals → assertNotEqual
|
|
84
|
+
- assertRegexpMatches → assertRegex
|
|
85
|
+
- And many more...
|
|
86
|
+
|
|
87
|
+
This recipe automatically renames these method calls to their non-deprecated versions.
|
|
88
|
+
|
|
89
|
+
Example:
|
|
90
|
+
Before:
|
|
91
|
+
class MyTest(unittest.TestCase):
|
|
92
|
+
def test_example(self):
|
|
93
|
+
self.assertEquals(1, 1)
|
|
94
|
+
self.assertRegexpMatches("hello", r"h.*o")
|
|
95
|
+
|
|
96
|
+
After:
|
|
97
|
+
class MyTest(unittest.TestCase):
|
|
98
|
+
def test_example(self):
|
|
99
|
+
self.assertEqual(1, 1)
|
|
100
|
+
self.assertRegex("hello", r"h.*o")
|
|
101
|
+
"""
|
|
102
|
+
|
|
103
|
+
@property
|
|
104
|
+
def name(self) -> str:
|
|
105
|
+
return "org.openrewrite.python.migrate.ReplaceUnittestDeprecatedAliases"
|
|
106
|
+
|
|
107
|
+
@property
|
|
108
|
+
def display_name(self) -> str:
|
|
109
|
+
return "Replace deprecated unittest method aliases"
|
|
110
|
+
|
|
111
|
+
@property
|
|
112
|
+
def description(self) -> str:
|
|
113
|
+
return (
|
|
114
|
+
"Replace deprecated unittest.TestCase method aliases like `assertEquals` "
|
|
115
|
+
"with their modern equivalents like `assertEqual`. These aliases were "
|
|
116
|
+
"removed in Python 3.11/3.12."
|
|
117
|
+
)
|
|
118
|
+
|
|
119
|
+
def editor(self) -> TreeVisitor[Any, ExecutionContext]:
|
|
120
|
+
class Visitor(PythonVisitor[ExecutionContext]):
|
|
121
|
+
def visit_method_invocation(
|
|
122
|
+
self, method: MethodInvocation, p: ExecutionContext
|
|
123
|
+
) -> Optional[MethodInvocation]:
|
|
124
|
+
method = super().visit_method_invocation(method, p)
|
|
125
|
+
|
|
126
|
+
if not isinstance(method.name, Identifier):
|
|
127
|
+
return method
|
|
128
|
+
|
|
129
|
+
method_name = method.name.simple_name
|
|
130
|
+
|
|
131
|
+
# Check if this is a deprecated unittest alias
|
|
132
|
+
if method_name in UNITTEST_ALIASES:
|
|
133
|
+
# Only replace if called on self (typical unittest pattern)
|
|
134
|
+
if _is_self_method(method):
|
|
135
|
+
new_name = UNITTEST_ALIASES[method_name]
|
|
136
|
+
return _rename_method(method, new_name)
|
|
137
|
+
|
|
138
|
+
return method
|
|
139
|
+
|
|
140
|
+
return Visitor()
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
"""Composite recipe for upgrading to LangChain 0.2."""
|
|
2
|
+
|
|
3
|
+
from typing import List
|
|
4
|
+
|
|
5
|
+
from rewrite import Recipe
|
|
6
|
+
from rewrite.category import CategoryDescriptor
|
|
7
|
+
from rewrite.decorators import categorize
|
|
8
|
+
from rewrite.marketplace import Python
|
|
9
|
+
|
|
10
|
+
_Migrate = [*Python, CategoryDescriptor(display_name="Migrate")]
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
@categorize(_Migrate)
|
|
14
|
+
class UpgradeToLangChain02(Recipe):
|
|
15
|
+
"""
|
|
16
|
+
Migrate to LangChain 0.2.
|
|
17
|
+
|
|
18
|
+
This composite recipe applies all necessary migrations for code using
|
|
19
|
+
LangChain 0.1 to be compatible with LangChain 0.2.
|
|
20
|
+
|
|
21
|
+
Key changes in LangChain 0.2:
|
|
22
|
+
- Third-party integrations moved from `langchain` to `langchain_community`
|
|
23
|
+
- Provider-specific classes should use dedicated packages (e.g. `langchain_openai`)
|
|
24
|
+
|
|
25
|
+
See: https://python.langchain.com/v0.2/docs/versions/v0_2/
|
|
26
|
+
"""
|
|
27
|
+
|
|
28
|
+
@property
|
|
29
|
+
def name(self) -> str:
|
|
30
|
+
return "org.openrewrite.python.migrate.langchain.UpgradeToLangChain02"
|
|
31
|
+
|
|
32
|
+
@property
|
|
33
|
+
def display_name(self) -> str:
|
|
34
|
+
return "Upgrade to LangChain 0.2"
|
|
35
|
+
|
|
36
|
+
@property
|
|
37
|
+
def description(self) -> str:
|
|
38
|
+
return (
|
|
39
|
+
"Migrate to LangChain 0.2 by updating imports from `langchain` "
|
|
40
|
+
"to `langchain_community` and provider-specific packages."
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
@property
|
|
44
|
+
def tags(self) -> List[str]:
|
|
45
|
+
return ["python", "migration", "langchain", "0.2"]
|
|
46
|
+
|
|
47
|
+
def recipe_list(self) -> List[Recipe]:
|
|
48
|
+
from .langchain_community_imports import ReplaceLangchainCommunityImports
|
|
49
|
+
from .langchain_provider_imports import ReplaceLangchainProviderImports
|
|
50
|
+
|
|
51
|
+
return [
|
|
52
|
+
# First move langchain -> langchain_community
|
|
53
|
+
ReplaceLangchainCommunityImports(),
|
|
54
|
+
# Then move langchain_community -> provider packages where possible
|
|
55
|
+
ReplaceLangchainProviderImports(),
|
|
56
|
+
]
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
"""Composite recipe for upgrading to LangChain 1.0."""
|
|
2
|
+
|
|
3
|
+
from typing import List
|
|
4
|
+
|
|
5
|
+
from rewrite import Recipe
|
|
6
|
+
from rewrite.category import CategoryDescriptor
|
|
7
|
+
from rewrite.decorators import categorize
|
|
8
|
+
from rewrite.marketplace import Python
|
|
9
|
+
|
|
10
|
+
_Migrate = [*Python, CategoryDescriptor(display_name="Migrate")]
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
@categorize(_Migrate)
|
|
14
|
+
class UpgradeToLangChain1(Recipe):
|
|
15
|
+
"""
|
|
16
|
+
Migrate to LangChain 1.0.
|
|
17
|
+
|
|
18
|
+
This composite recipe applies all necessary migrations for code using
|
|
19
|
+
earlier versions of LangChain to be compatible with LangChain 1.0.
|
|
20
|
+
|
|
21
|
+
Key changes in LangChain 1.0:
|
|
22
|
+
- Legacy chains, retrievers, and indexes moved to `langchain_classic`
|
|
23
|
+
- `create_react_agent` renamed to `create_agent`
|
|
24
|
+
- `initialize_agent`, `AgentExecutor`, `LLMChain` deprecated
|
|
25
|
+
- `hub` module moved to `langchain_classic`
|
|
26
|
+
|
|
27
|
+
See: https://docs.langchain.com/oss/python/migrate/langchain-v1
|
|
28
|
+
"""
|
|
29
|
+
|
|
30
|
+
@property
|
|
31
|
+
def name(self) -> str:
|
|
32
|
+
return "org.openrewrite.python.migrate.langchain.UpgradeToLangChain1"
|
|
33
|
+
|
|
34
|
+
@property
|
|
35
|
+
def display_name(self) -> str:
|
|
36
|
+
return "Upgrade to LangChain 1.0"
|
|
37
|
+
|
|
38
|
+
@property
|
|
39
|
+
def description(self) -> str:
|
|
40
|
+
return (
|
|
41
|
+
"Migrate to LangChain 1.0 by applying all v0.2 migrations and "
|
|
42
|
+
"then moving legacy functionality to `langchain_classic`."
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
@property
|
|
46
|
+
def tags(self) -> List[str]:
|
|
47
|
+
return ["python", "migration", "langchain", "1.0"]
|
|
48
|
+
|
|
49
|
+
def recipe_list(self) -> List[Recipe]:
|
|
50
|
+
from .langchain_classic_imports import (
|
|
51
|
+
FindDeprecatedLangchainAgents,
|
|
52
|
+
ReplaceLangchainClassicImports,
|
|
53
|
+
FindLangchainCreateReactAgent,
|
|
54
|
+
)
|
|
55
|
+
from .upgrade_to_langchain02 import UpgradeToLangChain02
|
|
56
|
+
|
|
57
|
+
return [
|
|
58
|
+
# First apply all v0.2 migrations
|
|
59
|
+
UpgradeToLangChain02(),
|
|
60
|
+
# Move legacy modules to langchain_classic
|
|
61
|
+
ReplaceLangchainClassicImports(),
|
|
62
|
+
# Rename create_react_agent to create_agent
|
|
63
|
+
FindLangchainCreateReactAgent(),
|
|
64
|
+
# Flag deprecated agent patterns
|
|
65
|
+
FindDeprecatedLangchainAgents(),
|
|
66
|
+
]
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
"""Composite recipe for upgrading from Python 3.9 to Python 3.10."""
|
|
2
|
+
|
|
3
|
+
from typing import List
|
|
4
|
+
|
|
5
|
+
from rewrite import Recipe
|
|
6
|
+
from rewrite.category import CategoryDescriptor
|
|
7
|
+
from rewrite.decorators import categorize
|
|
8
|
+
from rewrite.marketplace import Python
|
|
9
|
+
|
|
10
|
+
# Define category path: Python > Migrate
|
|
11
|
+
_Migrate = [*Python, CategoryDescriptor(display_name="Migrate")]
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@categorize(_Migrate)
|
|
15
|
+
class UpgradeToPython310(Recipe):
|
|
16
|
+
"""
|
|
17
|
+
Migrate deprecated APIs and adopt new syntax for Python 3.10 compatibility.
|
|
18
|
+
|
|
19
|
+
This composite recipe applies all necessary migrations for code
|
|
20
|
+
running on Python 3.9 to be compatible with Python 3.10.
|
|
21
|
+
|
|
22
|
+
Key changes in Python 3.10:
|
|
23
|
+
- PEP 604: Union types can be written as `X | Y` instead of `Union[X, Y]`
|
|
24
|
+
- `typing.Optional[X]` can be written as `X | None`
|
|
25
|
+
- `collections` ABCs removed from `collections` (use `collections.abc`)
|
|
26
|
+
- threading.currentThread() deprecated (use current_thread())
|
|
27
|
+
- threading.activeCount() deprecated (use active_count())
|
|
28
|
+
|
|
29
|
+
See: https://docs.python.org/3/whatsnew/3.10.html
|
|
30
|
+
"""
|
|
31
|
+
|
|
32
|
+
@property
|
|
33
|
+
def name(self) -> str:
|
|
34
|
+
return "org.openrewrite.python.migrate.UpgradeToPython310"
|
|
35
|
+
|
|
36
|
+
@property
|
|
37
|
+
def display_name(self) -> str:
|
|
38
|
+
return "Upgrade to Python 3.10"
|
|
39
|
+
|
|
40
|
+
@property
|
|
41
|
+
def description(self) -> str:
|
|
42
|
+
return (
|
|
43
|
+
"Migrate deprecated APIs and adopt new syntax for Python 3.10 compatibility. "
|
|
44
|
+
"This includes adopting PEP 604 union type syntax (`X | Y`) and other "
|
|
45
|
+
"modernizations between Python 3.9 and 3.10."
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
@property
|
|
49
|
+
def tags(self) -> List[str]:
|
|
50
|
+
return ["python", "migration", "3.10"]
|
|
51
|
+
|
|
52
|
+
def recipe_list(self) -> List[Recipe]:
|
|
53
|
+
"""Return the list of recipes to apply for Python 3.10 upgrade."""
|
|
54
|
+
# Import here to avoid circular imports
|
|
55
|
+
from .collections_abc_migrations import ReplaceCollectionsAbcImports
|
|
56
|
+
from .threading_deprecations import (
|
|
57
|
+
ReplaceConditionNotifyAll,
|
|
58
|
+
ReplaceEventIsSet,
|
|
59
|
+
ReplaceThreadGetName,
|
|
60
|
+
ReplaceThreadIsDaemon,
|
|
61
|
+
ReplaceThreadSetDaemon,
|
|
62
|
+
ReplaceThreadSetName,
|
|
63
|
+
ReplaceThreadingActiveCount,
|
|
64
|
+
ReplaceThreadingCurrentThread,
|
|
65
|
+
)
|
|
66
|
+
from .typing_union_to_pipe import (
|
|
67
|
+
ReplaceTypingOptionalWithUnion,
|
|
68
|
+
ReplaceTypingUnionWithPipe,
|
|
69
|
+
)
|
|
70
|
+
from .upgrade_to_python39 import UpgradeToPython39
|
|
71
|
+
|
|
72
|
+
return [
|
|
73
|
+
# First apply all Python 3.9 upgrades (which includes 3.8)
|
|
74
|
+
UpgradeToPython39(),
|
|
75
|
+
# collections ABCs moved to collections.abc, removed in Python 3.10
|
|
76
|
+
ReplaceCollectionsAbcImports(),
|
|
77
|
+
# PEP 604: Replace typing.Optional[X] with X | None
|
|
78
|
+
ReplaceTypingOptionalWithUnion(),
|
|
79
|
+
# PEP 604: Replace typing.Union[X, Y] with X | Y
|
|
80
|
+
ReplaceTypingUnionWithPipe(),
|
|
81
|
+
# Threading camelCase deprecations (deprecated 3.10, removed 3.12)
|
|
82
|
+
ReplaceThreadingCurrentThread(),
|
|
83
|
+
ReplaceThreadingActiveCount(),
|
|
84
|
+
ReplaceConditionNotifyAll(),
|
|
85
|
+
ReplaceEventIsSet(),
|
|
86
|
+
# Threading getter/setter deprecations (auto-fix)
|
|
87
|
+
ReplaceThreadGetName(),
|
|
88
|
+
ReplaceThreadSetName(),
|
|
89
|
+
ReplaceThreadIsDaemon(),
|
|
90
|
+
ReplaceThreadSetDaemon(),
|
|
91
|
+
]
|