openrewrite-migrate-python 0.14.0.dev20260904181306__tar.gz → 0.14.0.dev20260905202841__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 (160) hide show
  1. {openrewrite_migrate_python-0.14.0.dev20260904181306 → openrewrite_migrate_python-0.14.0.dev20260905202841}/PKG-INFO +1 -1
  2. {openrewrite_migrate_python-0.14.0.dev20260904181306 → openrewrite_migrate_python-0.14.0.dev20260905202841}/pyproject.toml +1 -1
  3. {openrewrite_migrate_python-0.14.0.dev20260904181306 → openrewrite_migrate_python-0.14.0.dev20260905202841}/src/openrewrite_migrate_python/migrate/_markers.py +9 -4
  4. {openrewrite_migrate_python-0.14.0.dev20260904181306 → openrewrite_migrate_python-0.14.0.dev20260905202841}/src/openrewrite_migrate_python/migrate/array_deprecations.py +9 -3
  5. {openrewrite_migrate_python-0.14.0.dev20260904181306 → openrewrite_migrate_python-0.14.0.dev20260905202841}/src/openrewrite_migrate_python/migrate/cgi_parse_deprecations.py +2 -2
  6. {openrewrite_migrate_python-0.14.0.dev20260904181306 → openrewrite_migrate_python-0.14.0.dev20260905202841}/src/openrewrite_migrate_python/migrate/configparser_deprecations.py +38 -19
  7. {openrewrite_migrate_python-0.14.0.dev20260904181306 → openrewrite_migrate_python-0.14.0.dev20260905202841}/src/openrewrite_migrate_python/migrate/distutils_migrations.py +16 -16
  8. {openrewrite_migrate_python-0.14.0.dev20260904181306 → openrewrite_migrate_python-0.14.0.dev20260905202841}/src/openrewrite_migrate_python/migrate/functools_deprecations.py +1 -1
  9. {openrewrite_migrate_python-0.14.0.dev20260904181306 → openrewrite_migrate_python-0.14.0.dev20260905202841}/src/openrewrite_migrate_python/migrate/html_parser_deprecations.py +1 -1
  10. {openrewrite_migrate_python-0.14.0.dev20260904181306 → openrewrite_migrate_python-0.14.0.dev20260905202841}/src/openrewrite_migrate_python/migrate/locale_getdefaultlocale_deprecation.py +1 -1
  11. {openrewrite_migrate_python-0.14.0.dev20260904181306 → openrewrite_migrate_python-0.14.0.dev20260905202841}/src/openrewrite_migrate_python/migrate/os_deprecations.py +1 -1
  12. {openrewrite_migrate_python-0.14.0.dev20260904181306 → openrewrite_migrate_python-0.14.0.dev20260905202841}/src/openrewrite_migrate_python/migrate/pathlib_deprecations.py +10 -6
  13. {openrewrite_migrate_python-0.14.0.dev20260904181306 → openrewrite_migrate_python-0.14.0.dev20260905202841}/src/openrewrite_migrate_python/migrate/re_deprecations.py +1 -1
  14. {openrewrite_migrate_python-0.14.0.dev20260904181306 → openrewrite_migrate_python-0.14.0.dev20260905202841}/src/openrewrite_migrate_python/migrate/shutil_deprecations.py +29 -17
  15. {openrewrite_migrate_python-0.14.0.dev20260904181306 → openrewrite_migrate_python-0.14.0.dev20260905202841}/src/openrewrite_migrate_python/migrate/socket_deprecations.py +7 -11
  16. {openrewrite_migrate_python-0.14.0.dev20260904181306 → openrewrite_migrate_python-0.14.0.dev20260905202841}/src/openrewrite_migrate_python/migrate/tarfile_deprecations.py +1 -1
  17. {openrewrite_migrate_python-0.14.0.dev20260904181306 → openrewrite_migrate_python-0.14.0.dev20260905202841}/src/openrewrite_migrate_python/migrate/tempfile_deprecations.py +1 -1
  18. {openrewrite_migrate_python-0.14.0.dev20260904181306 → openrewrite_migrate_python-0.14.0.dev20260905202841}/src/openrewrite_migrate_python/migrate/threading_deprecations.py +11 -5
  19. {openrewrite_migrate_python-0.14.0.dev20260904181306 → openrewrite_migrate_python-0.14.0.dev20260905202841}/src/openrewrite_migrate_python/migrate/threading_is_alive_deprecation.py +5 -2
  20. {openrewrite_migrate_python-0.14.0.dev20260904181306 → openrewrite_migrate_python-0.14.0.dev20260905202841}/src/openrewrite_migrate_python/migrate/urllib_deprecations.py +12 -13
  21. {openrewrite_migrate_python-0.14.0.dev20260904181306 → openrewrite_migrate_python-0.14.0.dev20260905202841}/src/openrewrite_migrate_python/migrate/xml_deprecations.py +2 -2
  22. {openrewrite_migrate_python-0.14.0.dev20260904181306 → openrewrite_migrate_python-0.14.0.dev20260905202841}/src/openrewrite_migrate_python.egg-info/PKG-INFO +1 -1
  23. {openrewrite_migrate_python-0.14.0.dev20260904181306 → openrewrite_migrate_python-0.14.0.dev20260905202841}/src/openrewrite_migrate_python.egg-info/SOURCES.txt +9 -0
  24. {openrewrite_migrate_python-0.14.0.dev20260904181306 → openrewrite_migrate_python-0.14.0.dev20260905202841}/tests/test_array_deprecations.py +25 -0
  25. {openrewrite_migrate_python-0.14.0.dev20260904181306 → openrewrite_migrate_python-0.14.0.dev20260905202841}/tests/test_collections_abc_migrations.py +0 -98
  26. {openrewrite_migrate_python-0.14.0.dev20260904181306 → openrewrite_migrate_python-0.14.0.dev20260905202841}/tests/test_configparser_deprecations.py +14 -36
  27. openrewrite_migrate_python-0.14.0.dev20260905202841/tests/test_distutils_migrations.py +37 -0
  28. openrewrite_migrate_python-0.14.0.dev20260905202841/tests/test_functools_deprecations.py +40 -0
  29. {openrewrite_migrate_python-0.14.0.dev20260904181306 → openrewrite_migrate_python-0.14.0.dev20260905202841}/tests/test_future_imports.py +9 -62
  30. {openrewrite_migrate_python-0.14.0.dev20260904181306 → openrewrite_migrate_python-0.14.0.dev20260905202841}/tests/test_langchain_community_imports.py +36 -134
  31. openrewrite_migrate_python-0.14.0.dev20260905202841/tests/test_langchain_provider_imports.py +86 -0
  32. openrewrite_migrate_python-0.14.0.dev20260905202841/tests/test_mailcap_migrations.py +25 -0
  33. openrewrite_migrate_python-0.14.0.dev20260905202841/tests/test_markers.py +31 -0
  34. {openrewrite_migrate_python-0.14.0.dev20260904181306 → openrewrite_migrate_python-0.14.0.dev20260905202841}/tests/test_os_deprecations.py +2 -2
  35. openrewrite_migrate_python-0.14.0.dev20260905202841/tests/test_pathlib_deprecations.py +72 -0
  36. openrewrite_migrate_python-0.14.0.dev20260905202841/tests/test_shutil_deprecations.py +59 -0
  37. openrewrite_migrate_python-0.14.0.dev20260905202841/tests/test_socket_deprecations.py +81 -0
  38. openrewrite_migrate_python-0.14.0.dev20260905202841/tests/test_tempfile_deprecations.py +40 -0
  39. {openrewrite_migrate_python-0.14.0.dev20260904181306 → openrewrite_migrate_python-0.14.0.dev20260905202841}/tests/test_threading_deprecations.py +4 -4
  40. {openrewrite_migrate_python-0.14.0.dev20260904181306 → openrewrite_migrate_python-0.14.0.dev20260905202841}/tests/test_threading_is_alive_deprecation.py +25 -0
  41. openrewrite_migrate_python-0.14.0.dev20260905202841/tests/test_urllib_deprecations.py +93 -0
  42. openrewrite_migrate_python-0.14.0.dev20260905202841/tests/test_xdrlib_migrations.py +25 -0
  43. openrewrite_migrate_python-0.14.0.dev20260904181306/tests/test_langchain_provider_imports.py +0 -228
  44. openrewrite_migrate_python-0.14.0.dev20260904181306/tests/test_shutil_deprecations.py +0 -26
  45. {openrewrite_migrate_python-0.14.0.dev20260904181306 → openrewrite_migrate_python-0.14.0.dev20260905202841}/setup.cfg +0 -0
  46. {openrewrite_migrate_python-0.14.0.dev20260904181306 → openrewrite_migrate_python-0.14.0.dev20260905202841}/src/openrewrite_code_quality_python/__init__.py +0 -0
  47. {openrewrite_migrate_python-0.14.0.dev20260904181306 → openrewrite_migrate_python-0.14.0.dev20260905202841}/src/openrewrite_code_quality_python/codequality/__init__.py +0 -0
  48. {openrewrite_migrate_python-0.14.0.dev20260904181306 → openrewrite_migrate_python-0.14.0.dev20260905202841}/src/openrewrite_code_quality_python/codequality/_reindent.py +0 -0
  49. {openrewrite_migrate_python-0.14.0.dev20260904181306 → openrewrite_migrate_python-0.14.0.dev20260905202841}/src/openrewrite_code_quality_python/codequality/_semantically_equal.py +0 -0
  50. {openrewrite_migrate_python-0.14.0.dev20260904181306 → openrewrite_migrate_python-0.14.0.dev20260905202841}/src/openrewrite_code_quality_python/codequality/_trivia.py +0 -0
  51. {openrewrite_migrate_python-0.14.0.dev20260904181306 → openrewrite_migrate_python-0.14.0.dev20260905202841}/src/openrewrite_code_quality_python/codequality/all_branches_identical.py +0 -0
  52. {openrewrite_migrate_python-0.14.0.dev20260904181306 → openrewrite_migrate_python-0.14.0.dev20260905202841}/src/openrewrite_code_quality_python/codequality/boolean_checks_not_inverted.py +0 -0
  53. {openrewrite_migrate_python-0.14.0.dev20260904181306 → openrewrite_migrate_python-0.14.0.dev20260905202841}/src/openrewrite_code_quality_python/codequality/collapsible_if_statements.py +0 -0
  54. {openrewrite_migrate_python-0.14.0.dev20260904181306 → openrewrite_migrate_python-0.14.0.dev20260905202841}/src/openrewrite_code_quality_python/codequality/find_suspicious_chained_comparison.py +0 -0
  55. {openrewrite_migrate_python-0.14.0.dev20260904181306 → openrewrite_migrate_python-0.14.0.dev20260905202841}/src/openrewrite_code_quality_python/codequality/merge_identical_branches.py +0 -0
  56. {openrewrite_migrate_python-0.14.0.dev20260904181306 → openrewrite_migrate_python-0.14.0.dev20260905202841}/src/openrewrite_code_quality_python/codequality/remove_duplicate_conditions.py +0 -0
  57. {openrewrite_migrate_python-0.14.0.dev20260904181306 → openrewrite_migrate_python-0.14.0.dev20260905202841}/src/openrewrite_code_quality_python/codequality/remove_self_assignment.py +0 -0
  58. {openrewrite_migrate_python-0.14.0.dev20260904181306 → openrewrite_migrate_python-0.14.0.dev20260905202841}/src/openrewrite_code_quality_python/codequality/remove_unconditional_value_overwrite.py +0 -0
  59. {openrewrite_migrate_python-0.14.0.dev20260904181306 → openrewrite_migrate_python-0.14.0.dev20260905202841}/src/openrewrite_code_quality_python/codequality/simplify_boolean_literal.py +0 -0
  60. {openrewrite_migrate_python-0.14.0.dev20260904181306 → openrewrite_migrate_python-0.14.0.dev20260905202841}/src/openrewrite_code_quality_python/codequality/simplify_redundant_logical_expression.py +0 -0
  61. {openrewrite_migrate_python-0.14.0.dev20260904181306 → openrewrite_migrate_python-0.14.0.dev20260905202841}/src/openrewrite_migrate_python/__init__.py +0 -0
  62. {openrewrite_migrate_python-0.14.0.dev20260904181306 → openrewrite_migrate_python-0.14.0.dev20260905202841}/src/openrewrite_migrate_python/migrate/__init__.py +0 -0
  63. {openrewrite_migrate_python-0.14.0.dev20260904181306 → openrewrite_migrate_python-0.14.0.dev20260905202841}/src/openrewrite_migrate_python/migrate/_from_imports.py +0 -0
  64. {openrewrite_migrate_python-0.14.0.dev20260904181306 → openrewrite_migrate_python-0.14.0.dev20260905202841}/src/openrewrite_migrate_python/migrate/_import_hygiene.py +0 -0
  65. {openrewrite_migrate_python-0.14.0.dev20260904181306 → openrewrite_migrate_python-0.14.0.dev20260905202841}/src/openrewrite_migrate_python/migrate/_langchain_tables.py +0 -0
  66. {openrewrite_migrate_python-0.14.0.dev20260904181306 → openrewrite_migrate_python-0.14.0.dev20260905202841}/src/openrewrite_migrate_python/migrate/_slots.py +0 -0
  67. {openrewrite_migrate_python-0.14.0.dev20260904181306 → openrewrite_migrate_python-0.14.0.dev20260905202841}/src/openrewrite_migrate_python/migrate/_typing_imports.py +0 -0
  68. {openrewrite_migrate_python-0.14.0.dev20260904181306 → openrewrite_migrate_python-0.14.0.dev20260905202841}/src/openrewrite_migrate_python/migrate/aifc_migrations.py +0 -0
  69. {openrewrite_migrate_python-0.14.0.dev20260904181306 → openrewrite_migrate_python-0.14.0.dev20260905202841}/src/openrewrite_migrate_python/migrate/ast_deprecations.py +0 -0
  70. {openrewrite_migrate_python-0.14.0.dev20260904181306 → openrewrite_migrate_python-0.14.0.dev20260905202841}/src/openrewrite_migrate_python/migrate/asyncio_coroutine_to_async.py +0 -0
  71. {openrewrite_migrate_python-0.14.0.dev20260904181306 → openrewrite_migrate_python-0.14.0.dev20260905202841}/src/openrewrite_migrate_python/migrate/asyncio_deprecations.py +0 -0
  72. {openrewrite_migrate_python-0.14.0.dev20260904181306 → openrewrite_migrate_python-0.14.0.dev20260905202841}/src/openrewrite_migrate_python/migrate/avro_migrations.py +0 -0
  73. {openrewrite_migrate_python-0.14.0.dev20260904181306 → openrewrite_migrate_python-0.14.0.dev20260905202841}/src/openrewrite_migrate_python/migrate/calendar_deprecations.py +0 -0
  74. {openrewrite_migrate_python-0.14.0.dev20260904181306 → openrewrite_migrate_python-0.14.0.dev20260905202841}/src/openrewrite_migrate_python/migrate/cgi_migrations.py +0 -0
  75. {openrewrite_migrate_python-0.14.0.dev20260904181306 → openrewrite_migrate_python-0.14.0.dev20260905202841}/src/openrewrite_migrate_python/migrate/collections_abc_migrations.py +0 -0
  76. {openrewrite_migrate_python-0.14.0.dev20260904181306 → openrewrite_migrate_python-0.14.0.dev20260905202841}/src/openrewrite_migrate_python/migrate/datetime_utc.py +0 -0
  77. {openrewrite_migrate_python-0.14.0.dev20260904181306 → openrewrite_migrate_python-0.14.0.dev20260905202841}/src/openrewrite_migrate_python/migrate/distutils_deprecations.py +0 -0
  78. {openrewrite_migrate_python-0.14.0.dev20260904181306 → openrewrite_migrate_python-0.14.0.dev20260905202841}/src/openrewrite_migrate_python/migrate/future_imports.py +0 -0
  79. {openrewrite_migrate_python-0.14.0.dev20260904181306 → openrewrite_migrate_python-0.14.0.dev20260905202841}/src/openrewrite_migrate_python/migrate/gettext_deprecations.py +0 -0
  80. {openrewrite_migrate_python-0.14.0.dev20260904181306 → openrewrite_migrate_python-0.14.0.dev20260905202841}/src/openrewrite_migrate_python/migrate/imp_migrations.py +0 -0
  81. {openrewrite_migrate_python-0.14.0.dev20260904181306 → openrewrite_migrate_python-0.14.0.dev20260905202841}/src/openrewrite_migrate_python/migrate/langchain_classic_imports.py +0 -0
  82. {openrewrite_migrate_python-0.14.0.dev20260904181306 → openrewrite_migrate_python-0.14.0.dev20260905202841}/src/openrewrite_migrate_python/migrate/langchain_community_imports.py +0 -0
  83. {openrewrite_migrate_python-0.14.0.dev20260904181306 → openrewrite_migrate_python-0.14.0.dev20260905202841}/src/openrewrite_migrate_python/migrate/langchain_provider_imports.py +0 -0
  84. {openrewrite_migrate_python-0.14.0.dev20260904181306 → openrewrite_migrate_python-0.14.0.dev20260905202841}/src/openrewrite_migrate_python/migrate/locale_deprecations.py +0 -0
  85. {openrewrite_migrate_python-0.14.0.dev20260904181306 → openrewrite_migrate_python-0.14.0.dev20260905202841}/src/openrewrite_migrate_python/migrate/macpath_deprecations.py +0 -0
  86. {openrewrite_migrate_python-0.14.0.dev20260904181306 → openrewrite_migrate_python-0.14.0.dev20260905202841}/src/openrewrite_migrate_python/migrate/mailcap_migrations.py +0 -0
  87. {openrewrite_migrate_python-0.14.0.dev20260904181306 → openrewrite_migrate_python-0.14.0.dev20260905202841}/src/openrewrite_migrate_python/migrate/nntplib_migrations.py +0 -0
  88. {openrewrite_migrate_python-0.14.0.dev20260904181306 → openrewrite_migrate_python-0.14.0.dev20260905202841}/src/openrewrite_migrate_python/migrate/pep594_system_migrations.py +0 -0
  89. {openrewrite_migrate_python-0.14.0.dev20260904181306 → openrewrite_migrate_python-0.14.0.dev20260905202841}/src/openrewrite_migrate_python/migrate/pipes_migrations.py +0 -0
  90. {openrewrite_migrate_python-0.14.0.dev20260904181306 → openrewrite_migrate_python-0.14.0.dev20260905202841}/src/openrewrite_migrate_python/migrate/pkgutil_deprecations.py +0 -0
  91. {openrewrite_migrate_python-0.14.0.dev20260904181306 → openrewrite_migrate_python-0.14.0.dev20260905202841}/src/openrewrite_migrate_python/migrate/platform_deprecations.py +0 -0
  92. {openrewrite_migrate_python-0.14.0.dev20260904181306 → openrewrite_migrate_python-0.14.0.dev20260905202841}/src/openrewrite_migrate_python/migrate/pydantic_deprecations.py +0 -0
  93. {openrewrite_migrate_python-0.14.0.dev20260904181306 → openrewrite_migrate_python-0.14.0.dev20260905202841}/src/openrewrite_migrate_python/migrate/pydantic_fields.py +0 -0
  94. {openrewrite_migrate_python-0.14.0.dev20260904181306 → openrewrite_migrate_python-0.14.0.dev20260905202841}/src/openrewrite_migrate_python/migrate/pydantic_model_fields.py +0 -0
  95. {openrewrite_migrate_python-0.14.0.dev20260904181306 → openrewrite_migrate_python-0.14.0.dev20260905202841}/src/openrewrite_migrate_python/migrate/removed_modules_312.py +0 -0
  96. {openrewrite_migrate_python-0.14.0.dev20260904181306 → openrewrite_migrate_python-0.14.0.dev20260905202841}/src/openrewrite_migrate_python/migrate/ssl_deprecations.py +0 -0
  97. {openrewrite_migrate_python-0.14.0.dev20260904181306 → openrewrite_migrate_python-0.14.0.dev20260905202841}/src/openrewrite_migrate_python/migrate/string_formatting.py +0 -0
  98. {openrewrite_migrate_python-0.14.0.dev20260904181306 → openrewrite_migrate_python-0.14.0.dev20260905202841}/src/openrewrite_migrate_python/migrate/sys_deprecations.py +0 -0
  99. {openrewrite_migrate_python-0.14.0.dev20260904181306 → openrewrite_migrate_python-0.14.0.dev20260905202841}/src/openrewrite_migrate_python/migrate/sys_last_deprecations.py +0 -0
  100. {openrewrite_migrate_python-0.14.0.dev20260904181306 → openrewrite_migrate_python-0.14.0.dev20260905202841}/src/openrewrite_migrate_python/migrate/telnetlib_migrations.py +0 -0
  101. {openrewrite_migrate_python-0.14.0.dev20260904181306 → openrewrite_migrate_python-0.14.0.dev20260905202841}/src/openrewrite_migrate_python/migrate/typing_callable.py +0 -0
  102. {openrewrite_migrate_python-0.14.0.dev20260904181306 → openrewrite_migrate_python-0.14.0.dev20260905202841}/src/openrewrite_migrate_python/migrate/typing_deprecations.py +0 -0
  103. {openrewrite_migrate_python-0.14.0.dev20260904181306 → openrewrite_migrate_python-0.14.0.dev20260905202841}/src/openrewrite_migrate_python/migrate/typing_union_to_pipe.py +0 -0
  104. {openrewrite_migrate_python-0.14.0.dev20260904181306 → openrewrite_migrate_python-0.14.0.dev20260905202841}/src/openrewrite_migrate_python/migrate/unittest_deprecations.py +0 -0
  105. {openrewrite_migrate_python-0.14.0.dev20260904181306 → openrewrite_migrate_python-0.14.0.dev20260905202841}/src/openrewrite_migrate_python/migrate/upgrade_to_langchain02.py +0 -0
  106. {openrewrite_migrate_python-0.14.0.dev20260904181306 → openrewrite_migrate_python-0.14.0.dev20260905202841}/src/openrewrite_migrate_python/migrate/upgrade_to_langchain1.py +0 -0
  107. {openrewrite_migrate_python-0.14.0.dev20260904181306 → openrewrite_migrate_python-0.14.0.dev20260905202841}/src/openrewrite_migrate_python/migrate/upgrade_to_pydantic.py +0 -0
  108. {openrewrite_migrate_python-0.14.0.dev20260904181306 → openrewrite_migrate_python-0.14.0.dev20260905202841}/src/openrewrite_migrate_python/migrate/upgrade_to_python310.py +0 -0
  109. {openrewrite_migrate_python-0.14.0.dev20260904181306 → openrewrite_migrate_python-0.14.0.dev20260905202841}/src/openrewrite_migrate_python/migrate/upgrade_to_python311.py +0 -0
  110. {openrewrite_migrate_python-0.14.0.dev20260904181306 → openrewrite_migrate_python-0.14.0.dev20260905202841}/src/openrewrite_migrate_python/migrate/upgrade_to_python312.py +0 -0
  111. {openrewrite_migrate_python-0.14.0.dev20260904181306 → openrewrite_migrate_python-0.14.0.dev20260905202841}/src/openrewrite_migrate_python/migrate/upgrade_to_python313.py +0 -0
  112. {openrewrite_migrate_python-0.14.0.dev20260904181306 → openrewrite_migrate_python-0.14.0.dev20260905202841}/src/openrewrite_migrate_python/migrate/upgrade_to_python314.py +0 -0
  113. {openrewrite_migrate_python-0.14.0.dev20260904181306 → openrewrite_migrate_python-0.14.0.dev20260905202841}/src/openrewrite_migrate_python/migrate/upgrade_to_python38.py +0 -0
  114. {openrewrite_migrate_python-0.14.0.dev20260904181306 → openrewrite_migrate_python-0.14.0.dev20260905202841}/src/openrewrite_migrate_python/migrate/upgrade_to_python39.py +0 -0
  115. {openrewrite_migrate_python-0.14.0.dev20260904181306 → openrewrite_migrate_python-0.14.0.dev20260905202841}/src/openrewrite_migrate_python/migrate/uu_migrations.py +0 -0
  116. {openrewrite_migrate_python-0.14.0.dev20260904181306 → openrewrite_migrate_python-0.14.0.dev20260905202841}/src/openrewrite_migrate_python/migrate/xdrlib_migrations.py +0 -0
  117. {openrewrite_migrate_python-0.14.0.dev20260904181306 → openrewrite_migrate_python-0.14.0.dev20260905202841}/src/openrewrite_migrate_python.egg-info/dependency_links.txt +0 -0
  118. {openrewrite_migrate_python-0.14.0.dev20260904181306 → openrewrite_migrate_python-0.14.0.dev20260905202841}/src/openrewrite_migrate_python.egg-info/entry_points.txt +0 -0
  119. {openrewrite_migrate_python-0.14.0.dev20260904181306 → openrewrite_migrate_python-0.14.0.dev20260905202841}/src/openrewrite_migrate_python.egg-info/requires.txt +0 -0
  120. {openrewrite_migrate_python-0.14.0.dev20260904181306 → openrewrite_migrate_python-0.14.0.dev20260905202841}/src/openrewrite_migrate_python.egg-info/top_level.txt +0 -0
  121. {openrewrite_migrate_python-0.14.0.dev20260904181306 → openrewrite_migrate_python-0.14.0.dev20260905202841}/tests/test_aifc_migrations.py +0 -0
  122. {openrewrite_migrate_python-0.14.0.dev20260904181306 → openrewrite_migrate_python-0.14.0.dev20260905202841}/tests/test_ast_deprecations.py +0 -0
  123. {openrewrite_migrate_python-0.14.0.dev20260904181306 → openrewrite_migrate_python-0.14.0.dev20260905202841}/tests/test_asyncio_coroutine_to_async.py +0 -0
  124. {openrewrite_migrate_python-0.14.0.dev20260904181306 → openrewrite_migrate_python-0.14.0.dev20260905202841}/tests/test_asyncio_deprecations.py +0 -0
  125. {openrewrite_migrate_python-0.14.0.dev20260904181306 → openrewrite_migrate_python-0.14.0.dev20260905202841}/tests/test_avro_migrations.py +0 -0
  126. {openrewrite_migrate_python-0.14.0.dev20260904181306 → openrewrite_migrate_python-0.14.0.dev20260905202841}/tests/test_calendar_deprecations.py +0 -0
  127. {openrewrite_migrate_python-0.14.0.dev20260904181306 → openrewrite_migrate_python-0.14.0.dev20260905202841}/tests/test_cgi_parse_deprecations.py +0 -0
  128. {openrewrite_migrate_python-0.14.0.dev20260904181306 → openrewrite_migrate_python-0.14.0.dev20260905202841}/tests/test_change_import_recipes.py +0 -0
  129. {openrewrite_migrate_python-0.14.0.dev20260904181306 → openrewrite_migrate_python-0.14.0.dev20260905202841}/tests/test_datetime_utc.py +0 -0
  130. {openrewrite_migrate_python-0.14.0.dev20260904181306 → openrewrite_migrate_python-0.14.0.dev20260905202841}/tests/test_distutils_deprecations.py +0 -0
  131. {openrewrite_migrate_python-0.14.0.dev20260904181306 → openrewrite_migrate_python-0.14.0.dev20260905202841}/tests/test_gettext_deprecations.py +0 -0
  132. {openrewrite_migrate_python-0.14.0.dev20260904181306 → openrewrite_migrate_python-0.14.0.dev20260905202841}/tests/test_html_parser_deprecations.py +0 -0
  133. {openrewrite_migrate_python-0.14.0.dev20260904181306 → openrewrite_migrate_python-0.14.0.dev20260905202841}/tests/test_imp_migrations.py +0 -0
  134. {openrewrite_migrate_python-0.14.0.dev20260904181306 → openrewrite_migrate_python-0.14.0.dev20260905202841}/tests/test_langchain_classic_imports.py +0 -0
  135. {openrewrite_migrate_python-0.14.0.dev20260904181306 → openrewrite_migrate_python-0.14.0.dev20260905202841}/tests/test_locale_deprecations.py +0 -0
  136. {openrewrite_migrate_python-0.14.0.dev20260904181306 → openrewrite_migrate_python-0.14.0.dev20260905202841}/tests/test_locale_getdefaultlocale_deprecation.py +0 -0
  137. {openrewrite_migrate_python-0.14.0.dev20260904181306 → openrewrite_migrate_python-0.14.0.dev20260905202841}/tests/test_macpath_deprecations.py +0 -0
  138. {openrewrite_migrate_python-0.14.0.dev20260904181306 → openrewrite_migrate_python-0.14.0.dev20260905202841}/tests/test_pep594_migrations.py +0 -0
  139. {openrewrite_migrate_python-0.14.0.dev20260904181306 → openrewrite_migrate_python-0.14.0.dev20260905202841}/tests/test_pep594_system_migrations.py +0 -0
  140. {openrewrite_migrate_python-0.14.0.dev20260904181306 → openrewrite_migrate_python-0.14.0.dev20260905202841}/tests/test_pkgutil_deprecations.py +0 -0
  141. {openrewrite_migrate_python-0.14.0.dev20260904181306 → openrewrite_migrate_python-0.14.0.dev20260905202841}/tests/test_platform_deprecations.py +0 -0
  142. {openrewrite_migrate_python-0.14.0.dev20260904181306 → openrewrite_migrate_python-0.14.0.dev20260905202841}/tests/test_pydantic_deprecations.py +0 -0
  143. {openrewrite_migrate_python-0.14.0.dev20260904181306 → openrewrite_migrate_python-0.14.0.dev20260905202841}/tests/test_pydantic_fields.py +0 -0
  144. {openrewrite_migrate_python-0.14.0.dev20260904181306 → openrewrite_migrate_python-0.14.0.dev20260905202841}/tests/test_pydantic_model_fields.py +0 -0
  145. {openrewrite_migrate_python-0.14.0.dev20260904181306 → openrewrite_migrate_python-0.14.0.dev20260905202841}/tests/test_re_deprecations.py +0 -0
  146. {openrewrite_migrate_python-0.14.0.dev20260904181306 → openrewrite_migrate_python-0.14.0.dev20260905202841}/tests/test_removed_modules_312.py +0 -0
  147. {openrewrite_migrate_python-0.14.0.dev20260904181306 → openrewrite_migrate_python-0.14.0.dev20260905202841}/tests/test_ssl_deprecations.py +0 -0
  148. {openrewrite_migrate_python-0.14.0.dev20260904181306 → openrewrite_migrate_python-0.14.0.dev20260905202841}/tests/test_string_formatting.py +0 -0
  149. {openrewrite_migrate_python-0.14.0.dev20260904181306 → openrewrite_migrate_python-0.14.0.dev20260905202841}/tests/test_sys_deprecations.py +0 -0
  150. {openrewrite_migrate_python-0.14.0.dev20260904181306 → openrewrite_migrate_python-0.14.0.dev20260905202841}/tests/test_sys_last_deprecations.py +0 -0
  151. {openrewrite_migrate_python-0.14.0.dev20260904181306 → openrewrite_migrate_python-0.14.0.dev20260905202841}/tests/test_tarfile_deprecations.py +0 -0
  152. {openrewrite_migrate_python-0.14.0.dev20260904181306 → openrewrite_migrate_python-0.14.0.dev20260905202841}/tests/test_threading_extended.py +0 -0
  153. {openrewrite_migrate_python-0.14.0.dev20260904181306 → openrewrite_migrate_python-0.14.0.dev20260905202841}/tests/test_typing_alias_moves.py +0 -0
  154. {openrewrite_migrate_python-0.14.0.dev20260904181306 → openrewrite_migrate_python-0.14.0.dev20260905202841}/tests/test_typing_callable.py +0 -0
  155. {openrewrite_migrate_python-0.14.0.dev20260904181306 → openrewrite_migrate_python-0.14.0.dev20260905202841}/tests/test_typing_deprecations.py +0 -0
  156. {openrewrite_migrate_python-0.14.0.dev20260904181306 → openrewrite_migrate_python-0.14.0.dev20260905202841}/tests/test_typing_union_to_pipe.py +0 -0
  157. {openrewrite_migrate_python-0.14.0.dev20260904181306 → openrewrite_migrate_python-0.14.0.dev20260905202841}/tests/test_unittest_deprecations.py +0 -0
  158. {openrewrite_migrate_python-0.14.0.dev20260904181306 → openrewrite_migrate_python-0.14.0.dev20260905202841}/tests/test_upgrade_recipes.py +0 -0
  159. {openrewrite_migrate_python-0.14.0.dev20260904181306 → openrewrite_migrate_python-0.14.0.dev20260905202841}/tests/test_upgrade_to_pydantic.py +0 -0
  160. {openrewrite_migrate_python-0.14.0.dev20260904181306 → openrewrite_migrate_python-0.14.0.dev20260905202841}/tests/test_xml_deprecations.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: openrewrite-migrate-python
3
- Version: 0.14.0.dev20260904181306
3
+ Version: 0.14.0.dev20260905202841
4
4
  Summary: OpenRewrite recipes for migrating Python codebases to newer Python versions.
5
5
  Author-email: "Moderne Inc." <support@moderne.io>
6
6
  License: Moderne Proprietary
@@ -5,7 +5,7 @@ build-backend = "setuptools.build_meta"
5
5
  [project]
6
6
  name = "openrewrite-migrate-python"
7
7
  description = "OpenRewrite recipes for migrating Python codebases to newer Python versions."
8
- version = "0.14.0.dev20260904181306" # Updated dynamically during release
8
+ version = "0.14.0.dev20260905202841" # Updated dynamically during release
9
9
  authors = [{ name = "Moderne Inc.", email = "support@moderne.io" }]
10
10
  license = { text = "Moderne Proprietary" }
11
11
  readme = "README.md"
@@ -15,8 +15,13 @@ def mark_deprecated(tree: Any, message: str, detail: Optional[str] = None) -> An
15
15
  output but surfaces as a warning diagnostic in the tooling.
16
16
  """
17
17
  full_message = f"{message}: {detail}" if detail else message
18
- warn_marker = MarkupWarn(random_id(), full_message)
19
18
  current_markers = tree.markers
20
- new_markers_list = list(current_markers.markers) + [warn_marker]
21
- new_markers = Markers(current_markers.id, new_markers_list)
22
- return tree.replace(_markers=new_markers)
19
+ # A run re-applies the recipe to its own output until nothing changes, so a tree already
20
+ # carrying this warning has to come back unchanged for the run to converge.
21
+ if any(
22
+ isinstance(m, MarkupWarn) and m.message == full_message
23
+ for m in current_markers.markers
24
+ ):
25
+ return tree
26
+ new_markers_list = list(current_markers.markers) + [MarkupWarn(random_id(), full_message)]
27
+ return tree.replace(_markers=Markers(current_markers.id, new_markers_list))
@@ -14,7 +14,7 @@ from rewrite import ExecutionContext, Preconditions, Recipe, TreeVisitor
14
14
  from rewrite.category import CategoryDescriptor
15
15
  from rewrite.decorators import categorize
16
16
  from rewrite.marketplace import Python
17
- from rewrite.python.preconditions import uses_method
17
+ from rewrite.python.preconditions import uses_import, uses_method
18
18
  from rewrite.python.visitor import PythonVisitor
19
19
  from rewrite.java.tree import Identifier, MethodInvocation
20
20
 
@@ -81,7 +81,10 @@ class ReplaceArrayTostring(Recipe):
81
81
  new_name = method.name.replace(_simple_name="tobytes")
82
82
  return method.replace(_name=new_name)
83
83
 
84
- return Preconditions.check(uses_method("*..* tostring(..)"), Visitor())
84
+ return Preconditions.check(
85
+ Preconditions.and_(uses_import("array"), uses_method("*..* tostring(..)")),
86
+ Visitor(),
87
+ )
85
88
 
86
89
 
87
90
  @categorize(_Python314)
@@ -137,4 +140,7 @@ class ReplaceArrayFromstring(Recipe):
137
140
  new_name = method.name.replace(_simple_name="frombytes")
138
141
  return method.replace(_name=new_name)
139
142
 
140
- return Preconditions.check(uses_method("*..* fromstring(..)"), Visitor())
143
+ return Preconditions.check(
144
+ Preconditions.and_(uses_import("array"), uses_method("*..* fromstring(..)")),
145
+ Visitor(),
146
+ )
@@ -136,7 +136,7 @@ class ReplaceCgiParseQs(Recipe):
136
136
  new_padded = old_padded.replace(_element=new_select)
137
137
  return method.padding.replace(_select=new_padded)
138
138
 
139
- return Preconditions.check(uses_method("*..* parse_qs(..)"), Visitor())
139
+ return Preconditions.check(uses_method("cgi parse_qs(..)"), Visitor())
140
140
 
141
141
 
142
142
  @categorize(_Python38)
@@ -202,4 +202,4 @@ class ReplaceCgiParseQsl(Recipe):
202
202
  new_padded = old_padded.replace(_element=new_select)
203
203
  return method.padding.replace(_select=new_padded)
204
204
 
205
- return Preconditions.check(uses_method("*..* parse_qsl(..)"), Visitor())
205
+ return Preconditions.check(uses_method("cgi parse_qsl(..)"), Visitor())
@@ -12,12 +12,15 @@ See: https://docs.python.org/3/library/configparser.html
12
12
 
13
13
  from typing import Any, Optional
14
14
 
15
- from rewrite import ExecutionContext, Recipe, TreeVisitor
15
+ from rewrite import Cursor, ExecutionContext, Preconditions, Recipe, TreeVisitor
16
16
  from rewrite.category import CategoryDescriptor
17
17
  from rewrite.decorators import categorize
18
18
  from rewrite.marketplace import Python
19
+ from rewrite.python.preconditions import uses_import, uses_method
20
+ from rewrite.python.scope_utils import LocalBindings
19
21
  from rewrite.python.visitor import PythonVisitor
20
- from rewrite.java.tree import Identifier, FieldAccess, MethodInvocation
22
+ from rewrite.python.tree import CompilationUnit
23
+ from rewrite.java.tree import Identifier, FieldAccess, J, MethodInvocation
21
24
 
22
25
  # Define category path: Python > Migrate > Python 3.12
23
26
  _Python312 = [
@@ -34,7 +37,18 @@ _Python313 = [
34
37
  ]
35
38
 
36
39
 
37
- def _is_configparser_attribute(field_access: FieldAccess, attr_name: str) -> bool:
40
+ def _names_the_module(node: Any, locals_: LocalBindings, cursor: Cursor) -> bool:
41
+ """Whether ``node`` is the `configparser` module rather than something else holding the name."""
42
+ return (
43
+ isinstance(node, Identifier)
44
+ and node.simple_name == "configparser"
45
+ and not locals_.is_bound(cursor, "configparser")
46
+ )
47
+
48
+
49
+ def _is_configparser_attribute(
50
+ field_access: FieldAccess, attr_name: str, locals_: LocalBindings, cursor: Cursor
51
+ ) -> bool:
38
52
  """
39
53
  Check if this is a configparser.attr_name access.
40
54
 
@@ -47,12 +61,7 @@ def _is_configparser_attribute(field_access: FieldAccess, attr_name: str) -> boo
47
61
  if field_access.name.simple_name != attr_name:
48
62
  return False
49
63
 
50
- # Check if the target is 'configparser'
51
- target = field_access.target
52
- if isinstance(target, Identifier) and target.simple_name == "configparser":
53
- return True
54
-
55
- return False
64
+ return _names_the_module(field_access.target, locals_, cursor)
56
65
 
57
66
 
58
67
  def _replace_configparser_attribute(field_access: FieldAccess, new_name: str) -> FieldAccess:
@@ -99,7 +108,9 @@ def _rename_method(method: MethodInvocation, new_name: str) -> MethodInvocation:
99
108
  return method.replace(_name=new_identifier)
100
109
 
101
110
 
102
- def _is_configparser_constructor(method: MethodInvocation, class_name: str) -> bool:
111
+ def _is_configparser_constructor(
112
+ method: MethodInvocation, class_name: str, locals_: LocalBindings, cursor: Cursor
113
+ ) -> bool:
103
114
  """
104
115
  Check if this is a configparser.ClassName() constructor call.
105
116
 
@@ -112,11 +123,7 @@ def _is_configparser_constructor(method: MethodInvocation, class_name: str) -> b
112
123
  if method.name.simple_name != class_name:
113
124
  return False
114
125
 
115
- # Check if the select is 'configparser'
116
- select = method.select
117
- if select is None:
118
- return False
119
- if isinstance(select, Identifier) and select.simple_name == "configparser":
126
+ if _names_the_module(method.select, locals_, cursor):
120
127
  return True
121
128
 
122
129
  return False
@@ -158,13 +165,23 @@ class ReplaceConfigparserSafeConfigParser(Recipe):
158
165
 
159
166
  def editor(self) -> TreeVisitor[Any, ExecutionContext]:
160
167
  class Visitor(PythonVisitor[ExecutionContext]):
168
+ def __init__(self) -> None:
169
+ super().__init__()
170
+ self._locals = LocalBindings()
171
+
172
+ def visit_compilation_unit(self, cu: CompilationUnit, p: ExecutionContext) -> J:
173
+ self._locals = LocalBindings()
174
+ return super().visit_compilation_unit(cu, p)
175
+
161
176
  def visit_method_invocation(
162
177
  self, method: MethodInvocation, p: ExecutionContext
163
178
  ) -> Optional[MethodInvocation]:
164
179
  method = super().visit_method_invocation(method, p)
165
180
 
166
181
  # Handle configparser.SafeConfigParser() constructor calls
167
- if _is_configparser_constructor(method, "SafeConfigParser"):
182
+ if _is_configparser_constructor(
183
+ method, "SafeConfigParser", self._locals, self.cursor
184
+ ):
168
185
  return _rename_method(method, "ConfigParser")
169
186
 
170
187
  return method
@@ -175,12 +192,14 @@ class ReplaceConfigparserSafeConfigParser(Recipe):
175
192
  field_access = super().visit_field_access(field_access, p)
176
193
 
177
194
  # Handle configparser.SafeConfigParser as a value (without calling)
178
- if _is_configparser_attribute(field_access, "SafeConfigParser"):
195
+ if _is_configparser_attribute(
196
+ field_access, "SafeConfigParser", self._locals, self.cursor
197
+ ):
179
198
  return _replace_configparser_attribute(field_access, "ConfigParser")
180
199
 
181
200
  return field_access
182
201
 
183
- return Visitor()
202
+ return Preconditions.check(uses_import("configparser"), Visitor())
184
203
 
185
204
 
186
205
  @categorize(_Python313)
@@ -232,4 +251,4 @@ class ReplaceConfigparserReadfp(Recipe):
232
251
 
233
252
  return method
234
253
 
235
- return Visitor()
254
+ return Preconditions.check(uses_method("configparser.*ConfigParser readfp(..)"), Visitor())
@@ -24,10 +24,13 @@ from rewrite.python.preconditions import uses_import
24
24
  from rewrite.category import CategoryDescriptor
25
25
  from rewrite.decorators import categorize
26
26
  from rewrite.marketplace import Python
27
+ from rewrite.python.import_utils import get_name_string, get_qualid_name
27
28
  from rewrite.python.visitor import PythonVisitor
28
29
  from rewrite.python.tree import MultiImport
29
30
  from ._markers import mark_deprecated
30
31
 
32
+ _DEPRECATED_CLASSES = frozenset({"LooseVersion", "StrictVersion"})
33
+
31
34
  # Define category path: Python > Migrate > Python 3.12
32
35
  _Python312 = [
33
36
  *Python,
@@ -95,21 +98,18 @@ class ReplaceDistutilsVersion(Recipe):
95
98
  ) -> Optional[MultiImport]:
96
99
  multi = super().visit_multi_import(multi, p)
97
100
 
98
- # Check the 'from' part for 'from distutils.version import ...'
99
- from_part = multi.from_
100
- if from_part is not None:
101
- from_str = from_part.print_all() if hasattr(from_part, 'print_all') else str(from_part)
102
- if 'distutils.version' in from_str:
103
- # Check what's being imported
104
- imports_str = multi.print_all() if hasattr(multi, 'print_all') else str(multi)
105
- if 'LooseVersion' in imports_str or 'StrictVersion' in imports_str:
106
- return mark_deprecated(
107
- multi,
108
- "distutils.version is deprecated",
109
- "Migrate to packaging.version.Version (removed in Python 3.12). "
110
- "Note: packaging.version.Version is not a drop-in replacement."
111
- )
112
-
113
- return multi
101
+ if multi.from_ is None or get_name_string(multi.from_) != "distutils.version":
102
+ return multi
103
+ if not any(
104
+ get_qualid_name(imp.qualid) in _DEPRECATED_CLASSES for imp in multi.names
105
+ ):
106
+ return multi
107
+
108
+ return mark_deprecated(
109
+ multi,
110
+ "distutils.version is deprecated",
111
+ "Migrate to packaging.version.Version (removed in Python 3.12). "
112
+ "Note: packaging.version.Version is not a drop-in replacement."
113
+ )
114
114
 
115
115
  return Preconditions.check(uses_import("distutils"), Visitor())
@@ -86,4 +86,4 @@ class FindFunctoolsCmpToKey(Recipe):
86
86
 
87
87
  return method
88
88
 
89
- return Preconditions.check(uses_method("*..* cmp_to_key(..)"), Visitor())
89
+ return Preconditions.check(uses_method("functools cmp_to_key(..)"), Visitor())
@@ -103,4 +103,4 @@ class ReplaceHtmlParserUnescape(Recipe):
103
103
 
104
104
  return method
105
105
 
106
- return Preconditions.check(uses_method("*..* unescape(..)"), Visitor())
106
+ return Preconditions.check(uses_method("html.parser.HTMLParser unescape(..)"), Visitor())
@@ -89,4 +89,4 @@ class FindLocaleGetdefaultlocale(Recipe):
89
89
  "locale.getpreferredencoding(False) instead."
90
90
  )
91
91
 
92
- return Preconditions.check(uses_method("*..* getdefaultlocale(..)"), Visitor())
92
+ return Preconditions.check(uses_method("locale getdefaultlocale(..)"), Visitor())
@@ -81,7 +81,7 @@ class FindOsPopen(Recipe):
81
81
 
82
82
  return method
83
83
 
84
- return Preconditions.check(uses_method("*..* popen(..)"), Visitor())
84
+ return Preconditions.check(uses_method("os popen(..)"), Visitor())
85
85
 
86
86
 
87
87
  @categorize(_Migrate)
@@ -13,11 +13,15 @@ from rewrite import ExecutionContext, Preconditions, Recipe, TreeVisitor
13
13
  from rewrite.category import CategoryDescriptor
14
14
  from rewrite.decorators import categorize
15
15
  from rewrite.marketplace import Python
16
+ from rewrite.python.method_matcher import MethodMatcher
16
17
  from rewrite.python.preconditions import uses_method
17
18
  from rewrite.python.visitor import PythonVisitor
18
- from rewrite.java.tree import Identifier, MethodInvocation
19
+ from rewrite.java.tree import MethodInvocation
19
20
  from ._markers import mark_deprecated
20
21
 
22
+ _LINK_TO = "pathlib.Path link_to(..)"
23
+ _LINK_TO_MATCHER = MethodMatcher.create(_LINK_TO)
24
+
21
25
  # Define category path: Python > Migrate > Python 3.12
22
26
  _Python312 = [
23
27
  *Python,
@@ -61,7 +65,9 @@ class FindPathlibLinkTo(Recipe):
61
65
  def description(self) -> str:
62
66
  return (
63
67
  "Find usage of `Path.link_to()` which was deprecated in Python 3.10 "
64
- "and removed in 3.12. Use `hardlink_to()` instead (note: argument order is reversed)."
68
+ "and removed in 3.12. Use `hardlink_to()` instead (note: argument order is reversed). "
69
+ "`link_to` is not a name reserved to `pathlib`, so this only reports calls whose "
70
+ "receiver resolves to a `Path`; a parse without type attribution reports nothing."
65
71
  )
66
72
 
67
73
  @property
@@ -75,9 +81,7 @@ class FindPathlibLinkTo(Recipe):
75
81
  ) -> Optional[MethodInvocation]:
76
82
  method = super().visit_method_invocation(method, p)
77
83
 
78
- if not isinstance(method.name, Identifier):
79
- return method
80
- if method.name.simple_name != "link_to":
84
+ if not _LINK_TO_MATCHER.matches(method):
81
85
  return method
82
86
 
83
87
  return mark_deprecated(
@@ -86,4 +90,4 @@ class FindPathlibLinkTo(Recipe):
86
90
  "Use hardlink_to() instead (note: argument order is reversed)."
87
91
  )
88
92
 
89
- return Preconditions.check(uses_method("*..* link_to(..)"), Visitor())
93
+ return Preconditions.check(uses_method(_LINK_TO), Visitor())
@@ -118,7 +118,7 @@ class ReplaceReTemplate(Recipe):
118
118
 
119
119
  return Preconditions.check(
120
120
  Preconditions.or_(
121
- uses_method("*..* template(..)"),
121
+ uses_method("re template(..)"),
122
122
  uses_type("re"),
123
123
  ),
124
124
  Visitor(),
@@ -13,11 +13,36 @@ from rewrite import ExecutionContext, Preconditions, Recipe, TreeVisitor
13
13
  from rewrite.category import CategoryDescriptor
14
14
  from rewrite.decorators import categorize
15
15
  from rewrite.marketplace import Python
16
+ from rewrite.python.method_matcher import MethodMatcher
16
17
  from rewrite.python.preconditions import uses_method
17
18
  from rewrite.python.visitor import PythonVisitor
18
- from rewrite.java.tree import Identifier, MethodInvocation
19
+ from rewrite.java.tree import Identifier, Literal, MethodInvocation
20
+ from rewrite.python.tree import NamedArgument
19
21
  from ._markers import mark_deprecated
20
22
 
23
+ _RMTREE = "shutil rmtree(..)"
24
+ _RMTREE_MATCHER = MethodMatcher.create(_RMTREE)
25
+
26
+
27
+ def _supplies_onerror(method: MethodInvocation) -> bool:
28
+ """Whether the call passes a callback for `onerror`, by keyword or in its position.
29
+
30
+ `rmtree(path, ignore_errors, onerror)` puts `onerror` third, and an explicit `None`
31
+ there means the same as omitting it.
32
+ """
33
+ def is_none(expr: Any) -> bool:
34
+ return isinstance(expr, (Identifier, Literal)) and str(
35
+ getattr(expr, "simple_name", None) or getattr(expr, "value_source", None)
36
+ ) == "None"
37
+
38
+ for index, arg in enumerate(method.arguments):
39
+ if isinstance(arg, NamedArgument):
40
+ if isinstance(arg.name, Identifier) and arg.name.simple_name == "onerror":
41
+ return not is_none(arg.value)
42
+ elif index == 2:
43
+ return not is_none(arg)
44
+ return False
45
+
21
46
  # Define category path: Python > Migrate > Python 3.12
22
47
  _Python312 = [
23
48
  *Python,
@@ -75,23 +100,10 @@ class FindShutilRmtreeOnerror(Recipe):
75
100
  ) -> Optional[MethodInvocation]:
76
101
  method = super().visit_method_invocation(method, p)
77
102
 
78
- if not isinstance(method.name, Identifier):
79
- return method
80
- if method.name.simple_name != "rmtree":
81
- return method
82
-
83
- select = method.select
84
- if not isinstance(select, Identifier):
85
- return method
86
- if select.simple_name != "shutil":
103
+ if not _RMTREE_MATCHER.matches(method):
87
104
  return method
88
105
 
89
- # Check if any argument uses `onerror=` keyword
90
- # We look at the string representation of arguments for keyword args
91
- # Since we can't easily inspect keyword args at the AST level
92
- # without type attribution, we mark all shutil.rmtree() calls
93
- # as needing review if they have 3+ arguments (path, ignore_errors, onerror)
94
- if len(method.arguments) >= 3:
106
+ if _supplies_onerror(method):
95
107
  return mark_deprecated(
96
108
  method,
97
109
  "shutil.rmtree() `onerror` parameter was deprecated in Python 3.12. "
@@ -100,4 +112,4 @@ class FindShutilRmtreeOnerror(Recipe):
100
112
 
101
113
  return method
102
114
 
103
- return Preconditions.check(uses_method("*..* rmtree(..)"), Visitor())
115
+ return Preconditions.check(uses_method(_RMTREE), Visitor())
@@ -15,11 +15,15 @@ from rewrite import ExecutionContext, Preconditions, Recipe, TreeVisitor
15
15
  from rewrite.category import CategoryDescriptor
16
16
  from rewrite.decorators import categorize
17
17
  from rewrite.marketplace import Python
18
+ from rewrite.python.method_matcher import MethodMatcher
18
19
  from rewrite.python.preconditions import uses_method
19
20
  from rewrite.python.visitor import PythonVisitor
20
- from rewrite.java.tree import Identifier, MethodInvocation
21
+ from rewrite.java.tree import MethodInvocation
21
22
  from ._markers import mark_deprecated
22
23
 
24
+ _GETFQDN = "socket getfqdn(..)"
25
+ _GETFQDN_MATCHER = MethodMatcher.create(_GETFQDN)
26
+
23
27
  # Define category path: Python > Migrate > Python 3.11
24
28
  _Python311 = [
25
29
  *Python,
@@ -67,15 +71,7 @@ class FindSocketGetFQDN(Recipe):
67
71
  ) -> Optional[MethodInvocation]:
68
72
  method = super().visit_method_invocation(method, p)
69
73
 
70
- if not isinstance(method.name, Identifier):
71
- return method
72
- if method.name.simple_name != "getfqdn":
73
- return method
74
-
75
- select = method.select
76
- if not isinstance(select, Identifier):
77
- return method
78
- if select.simple_name != "socket":
74
+ if not _GETFQDN_MATCHER.matches(method):
79
75
  return method
80
76
 
81
77
  return mark_deprecated(
@@ -84,4 +80,4 @@ class FindSocketGetFQDN(Recipe):
84
80
  "Consider using socket.gethostname() instead."
85
81
  )
86
82
 
87
- return Preconditions.check(uses_method("*..* getfqdn(..)"), Visitor())
83
+ return Preconditions.check(uses_method(_GETFQDN), Visitor())
@@ -106,7 +106,7 @@ class ReplaceTarfileFilemode(Recipe):
106
106
 
107
107
  return Preconditions.check(
108
108
  Preconditions.or_(
109
- uses_method("*..* filemode(..)"),
109
+ uses_method("tarfile filemode(..)"),
110
110
  uses_type("tarfile"),
111
111
  ),
112
112
  Visitor(),
@@ -101,4 +101,4 @@ class FindTempfileMktemp(Recipe):
101
101
  "Use tempfile.mkstemp() or NamedTemporaryFile() instead."
102
102
  )
103
103
 
104
- return Preconditions.check(uses_method("*..* mktemp(..)"), Visitor())
104
+ return Preconditions.check(uses_method("tempfile mktemp(..)"), Visitor())
@@ -21,7 +21,7 @@ from rewrite import ExecutionContext, Preconditions, Recipe, TreeVisitor
21
21
  from rewrite.category import CategoryDescriptor
22
22
  from rewrite.decorators import categorize
23
23
  from rewrite.marketplace import Python
24
- from rewrite.python.preconditions import uses_method
24
+ from rewrite.python.preconditions import uses_import, uses_method
25
25
  from rewrite.python.visitor import PythonVisitor
26
26
  from rewrite.python.template import pattern, template, capture
27
27
  from rewrite.java.tree import Identifier, MethodInvocation
@@ -95,7 +95,7 @@ class ReplaceThreadingCurrentThread(Recipe):
95
95
  new_name = method.name.replace(_simple_name="current_thread")
96
96
  return method.replace(_name=new_name)
97
97
 
98
- return Preconditions.check(uses_method("*..* currentThread(..)"), Visitor())
98
+ return Preconditions.check(uses_method("threading currentThread(..)"), Visitor())
99
99
 
100
100
 
101
101
  @categorize(_Python310)
@@ -157,7 +157,7 @@ class ReplaceThreadingActiveCount(Recipe):
157
157
  new_name = method.name.replace(_simple_name="active_count")
158
158
  return method.replace(_name=new_name)
159
159
 
160
- return Preconditions.check(uses_method("*..* activeCount(..)"), Visitor())
160
+ return Preconditions.check(uses_method("threading activeCount(..)"), Visitor())
161
161
 
162
162
 
163
163
  @categorize(_Python310)
@@ -216,7 +216,10 @@ class ReplaceConditionNotifyAll(Recipe):
216
216
  new_name = method.name.replace(_simple_name="notify_all")
217
217
  return method.replace(_name=new_name)
218
218
 
219
- return Preconditions.check(uses_method("*..* notifyAll(..)"), Visitor())
219
+ return Preconditions.check(
220
+ Preconditions.and_(uses_import("threading"), uses_method("*..* notifyAll(..)")),
221
+ Visitor(),
222
+ )
220
223
 
221
224
 
222
225
  # Pattern/template pairs for getter-to-property conversions
@@ -296,7 +299,10 @@ class ReplaceEventIsSet(Recipe):
296
299
  new_name = method.name.replace(_simple_name="is_set")
297
300
  return method.replace(_name=new_name)
298
301
 
299
- return Preconditions.check(uses_method("*..* isSet(..)"), Visitor())
302
+ return Preconditions.check(
303
+ Preconditions.and_(uses_import("threading"), uses_method("*..* isSet(..)")),
304
+ Visitor(),
305
+ )
300
306
 
301
307
 
302
308
  @categorize(_Python310)
@@ -13,7 +13,7 @@ from rewrite import ExecutionContext, Preconditions, Recipe, TreeVisitor
13
13
  from rewrite.category import CategoryDescriptor
14
14
  from rewrite.decorators import categorize
15
15
  from rewrite.marketplace import Python
16
- from rewrite.python.preconditions import uses_method
16
+ from rewrite.python.preconditions import uses_import, uses_method
17
17
  from rewrite.python.visitor import PythonVisitor
18
18
  from rewrite.java.tree import Identifier, MethodInvocation
19
19
 
@@ -84,4 +84,7 @@ class ReplaceThreadIsAlive(Recipe):
84
84
  new_name = method.name.replace(_simple_name="is_alive")
85
85
  return method.replace(_name=new_name)
86
86
 
87
- return Preconditions.check(uses_method("*..* isAlive(..)"), Visitor())
87
+ return Preconditions.check(
88
+ Preconditions.and_(uses_import("threading"), uses_method("*..* isAlive(..)")),
89
+ Visitor(),
90
+ )
@@ -23,6 +23,7 @@ from rewrite import ExecutionContext, Preconditions, Recipe, TreeVisitor
23
23
  from rewrite.category import CategoryDescriptor
24
24
  from rewrite.decorators import categorize
25
25
  from rewrite.marketplace import Python
26
+ from rewrite.python.method_matcher import MethodMatcher
26
27
  from rewrite.python.preconditions import uses_method
27
28
  from rewrite.python.visitor import PythonVisitor
28
29
  from rewrite.java.tree import Identifier, MethodInvocation, FieldAccess
@@ -139,6 +140,10 @@ class FindUrllibParseSplitFunctions(Recipe):
139
140
  )
140
141
 
141
142
 
143
+ _TO_BYTES = "urllib.parse to_bytes(..)"
144
+ _TO_BYTES_MATCHER = MethodMatcher.create(_TO_BYTES)
145
+
146
+
142
147
  @categorize(_Python314)
143
148
  class FindUrllibParseToBytes(Recipe):
144
149
  """
@@ -182,19 +187,13 @@ class FindUrllibParseToBytes(Recipe):
182
187
  ) -> Optional[MethodInvocation]:
183
188
  method = super().visit_method_invocation(method, p)
184
189
 
185
- if not isinstance(method.name, Identifier):
186
- return method
187
- if method.name.simple_name != "to_bytes":
190
+ if not _TO_BYTES_MATCHER.matches(method):
188
191
  return method
189
192
 
190
- select = method.select
191
- if isinstance(select, Identifier) and select.simple_name == "parse":
192
- return mark_deprecated(
193
- method,
194
- "urllib.parse.to_bytes() was removed in Python 3.14. "
195
- "Use str.encode() directly instead."
196
- )
197
-
198
- return method
193
+ return mark_deprecated(
194
+ method,
195
+ "urllib.parse.to_bytes() was removed in Python 3.14. "
196
+ "Use str.encode() directly instead."
197
+ )
199
198
 
200
- return Preconditions.check(uses_method("*..* to_bytes(..)"), Visitor())
199
+ return Preconditions.check(uses_method(_TO_BYTES), Visitor())
@@ -115,7 +115,7 @@ class ReplaceElementGetchildren(Recipe):
115
115
 
116
116
  return result
117
117
 
118
- return Preconditions.check(uses_method("*..* getchildren(..)"), Visitor())
118
+ return Preconditions.check(uses_method("xml.etree..* getchildren(..)"), Visitor())
119
119
 
120
120
 
121
121
  @categorize(_Python39)
@@ -185,4 +185,4 @@ class ReplaceElementGetiterator(Recipe):
185
185
  new_name = method.name.replace(_simple_name="iter")
186
186
  return method.replace(_name=new_name)
187
187
 
188
- return Preconditions.check(uses_method("*..* getiterator(..)"), Visitor())
188
+ return Preconditions.check(uses_method("xml.etree..* getiterator(..)"), Visitor())
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: openrewrite-migrate-python
3
- Version: 0.14.0.dev20260904181306
3
+ Version: 0.14.0.dev20260905202841
4
4
  Summary: OpenRewrite recipes for migrating Python codebases to newer Python versions.
5
5
  Author-email: "Moderne Inc." <support@moderne.io>
6
6
  License: Moderne Proprietary