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,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
+ ]