openrewrite-migrate-python 0.14.0.dev20260902170552__tar.gz → 0.14.0.dev20260903170551__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 (150) hide show
  1. {openrewrite_migrate_python-0.14.0.dev20260902170552 → openrewrite_migrate_python-0.14.0.dev20260903170551}/PKG-INFO +1 -1
  2. {openrewrite_migrate_python-0.14.0.dev20260902170552 → openrewrite_migrate_python-0.14.0.dev20260903170551}/pyproject.toml +1 -1
  3. openrewrite_migrate_python-0.14.0.dev20260903170551/src/openrewrite_migrate_python/migrate/_from_imports.py +57 -0
  4. {openrewrite_migrate_python-0.14.0.dev20260902170552 → openrewrite_migrate_python-0.14.0.dev20260903170551}/src/openrewrite_migrate_python/migrate/gettext_deprecations.py +26 -4
  5. {openrewrite_migrate_python-0.14.0.dev20260902170552 → openrewrite_migrate_python-0.14.0.dev20260903170551}/src/openrewrite_migrate_python/migrate/locale_deprecations.py +33 -8
  6. {openrewrite_migrate_python-0.14.0.dev20260902170552 → openrewrite_migrate_python-0.14.0.dev20260903170551}/src/openrewrite_migrate_python/migrate/locale_getdefaultlocale_deprecation.py +8 -10
  7. {openrewrite_migrate_python-0.14.0.dev20260902170552 → openrewrite_migrate_python-0.14.0.dev20260903170551}/src/openrewrite_migrate_python/migrate/platform_deprecations.py +47 -18
  8. {openrewrite_migrate_python-0.14.0.dev20260902170552 → openrewrite_migrate_python-0.14.0.dev20260903170551}/src/openrewrite_migrate_python/migrate/ssl_deprecations.py +13 -2
  9. {openrewrite_migrate_python-0.14.0.dev20260902170552 → openrewrite_migrate_python-0.14.0.dev20260903170551}/src/openrewrite_migrate_python.egg-info/PKG-INFO +1 -1
  10. {openrewrite_migrate_python-0.14.0.dev20260902170552 → openrewrite_migrate_python-0.14.0.dev20260903170551}/src/openrewrite_migrate_python.egg-info/SOURCES.txt +1 -0
  11. {openrewrite_migrate_python-0.14.0.dev20260902170552 → openrewrite_migrate_python-0.14.0.dev20260903170551}/tests/test_gettext_deprecations.py +16 -0
  12. openrewrite_migrate_python-0.14.0.dev20260903170551/tests/test_locale_deprecations.py +110 -0
  13. openrewrite_migrate_python-0.14.0.dev20260903170551/tests/test_locale_getdefaultlocale_deprecation.py +45 -0
  14. {openrewrite_migrate_python-0.14.0.dev20260902170552 → openrewrite_migrate_python-0.14.0.dev20260903170551}/tests/test_platform_deprecations.py +28 -8
  15. {openrewrite_migrate_python-0.14.0.dev20260902170552 → openrewrite_migrate_python-0.14.0.dev20260903170551}/tests/test_ssl_deprecations.py +16 -0
  16. openrewrite_migrate_python-0.14.0.dev20260902170552/tests/test_locale_deprecations.py +0 -53
  17. openrewrite_migrate_python-0.14.0.dev20260902170552/tests/test_locale_getdefaultlocale_deprecation.py +0 -26
  18. {openrewrite_migrate_python-0.14.0.dev20260902170552 → openrewrite_migrate_python-0.14.0.dev20260903170551}/setup.cfg +0 -0
  19. {openrewrite_migrate_python-0.14.0.dev20260902170552 → openrewrite_migrate_python-0.14.0.dev20260903170551}/src/openrewrite_code_quality_python/__init__.py +0 -0
  20. {openrewrite_migrate_python-0.14.0.dev20260902170552 → openrewrite_migrate_python-0.14.0.dev20260903170551}/src/openrewrite_code_quality_python/codequality/__init__.py +0 -0
  21. {openrewrite_migrate_python-0.14.0.dev20260902170552 → openrewrite_migrate_python-0.14.0.dev20260903170551}/src/openrewrite_code_quality_python/codequality/_reindent.py +0 -0
  22. {openrewrite_migrate_python-0.14.0.dev20260902170552 → openrewrite_migrate_python-0.14.0.dev20260903170551}/src/openrewrite_code_quality_python/codequality/_semantically_equal.py +0 -0
  23. {openrewrite_migrate_python-0.14.0.dev20260902170552 → openrewrite_migrate_python-0.14.0.dev20260903170551}/src/openrewrite_code_quality_python/codequality/_trivia.py +0 -0
  24. {openrewrite_migrate_python-0.14.0.dev20260902170552 → openrewrite_migrate_python-0.14.0.dev20260903170551}/src/openrewrite_code_quality_python/codequality/all_branches_identical.py +0 -0
  25. {openrewrite_migrate_python-0.14.0.dev20260902170552 → openrewrite_migrate_python-0.14.0.dev20260903170551}/src/openrewrite_code_quality_python/codequality/boolean_checks_not_inverted.py +0 -0
  26. {openrewrite_migrate_python-0.14.0.dev20260902170552 → openrewrite_migrate_python-0.14.0.dev20260903170551}/src/openrewrite_code_quality_python/codequality/collapsible_if_statements.py +0 -0
  27. {openrewrite_migrate_python-0.14.0.dev20260902170552 → openrewrite_migrate_python-0.14.0.dev20260903170551}/src/openrewrite_code_quality_python/codequality/find_suspicious_chained_comparison.py +0 -0
  28. {openrewrite_migrate_python-0.14.0.dev20260902170552 → openrewrite_migrate_python-0.14.0.dev20260903170551}/src/openrewrite_code_quality_python/codequality/merge_identical_branches.py +0 -0
  29. {openrewrite_migrate_python-0.14.0.dev20260902170552 → openrewrite_migrate_python-0.14.0.dev20260903170551}/src/openrewrite_code_quality_python/codequality/remove_duplicate_conditions.py +0 -0
  30. {openrewrite_migrate_python-0.14.0.dev20260902170552 → openrewrite_migrate_python-0.14.0.dev20260903170551}/src/openrewrite_code_quality_python/codequality/remove_self_assignment.py +0 -0
  31. {openrewrite_migrate_python-0.14.0.dev20260902170552 → openrewrite_migrate_python-0.14.0.dev20260903170551}/src/openrewrite_code_quality_python/codequality/remove_unconditional_value_overwrite.py +0 -0
  32. {openrewrite_migrate_python-0.14.0.dev20260902170552 → openrewrite_migrate_python-0.14.0.dev20260903170551}/src/openrewrite_code_quality_python/codequality/simplify_boolean_literal.py +0 -0
  33. {openrewrite_migrate_python-0.14.0.dev20260902170552 → openrewrite_migrate_python-0.14.0.dev20260903170551}/src/openrewrite_code_quality_python/codequality/simplify_redundant_logical_expression.py +0 -0
  34. {openrewrite_migrate_python-0.14.0.dev20260902170552 → openrewrite_migrate_python-0.14.0.dev20260903170551}/src/openrewrite_migrate_python/__init__.py +0 -0
  35. {openrewrite_migrate_python-0.14.0.dev20260902170552 → openrewrite_migrate_python-0.14.0.dev20260903170551}/src/openrewrite_migrate_python/migrate/__init__.py +0 -0
  36. {openrewrite_migrate_python-0.14.0.dev20260902170552 → openrewrite_migrate_python-0.14.0.dev20260903170551}/src/openrewrite_migrate_python/migrate/_import_hygiene.py +0 -0
  37. {openrewrite_migrate_python-0.14.0.dev20260902170552 → openrewrite_migrate_python-0.14.0.dev20260903170551}/src/openrewrite_migrate_python/migrate/_langchain_tables.py +0 -0
  38. {openrewrite_migrate_python-0.14.0.dev20260902170552 → openrewrite_migrate_python-0.14.0.dev20260903170551}/src/openrewrite_migrate_python/migrate/_markers.py +0 -0
  39. {openrewrite_migrate_python-0.14.0.dev20260902170552 → openrewrite_migrate_python-0.14.0.dev20260903170551}/src/openrewrite_migrate_python/migrate/_typing_imports.py +0 -0
  40. {openrewrite_migrate_python-0.14.0.dev20260902170552 → openrewrite_migrate_python-0.14.0.dev20260903170551}/src/openrewrite_migrate_python/migrate/aifc_migrations.py +0 -0
  41. {openrewrite_migrate_python-0.14.0.dev20260902170552 → openrewrite_migrate_python-0.14.0.dev20260903170551}/src/openrewrite_migrate_python/migrate/array_deprecations.py +0 -0
  42. {openrewrite_migrate_python-0.14.0.dev20260902170552 → openrewrite_migrate_python-0.14.0.dev20260903170551}/src/openrewrite_migrate_python/migrate/ast_deprecations.py +0 -0
  43. {openrewrite_migrate_python-0.14.0.dev20260902170552 → openrewrite_migrate_python-0.14.0.dev20260903170551}/src/openrewrite_migrate_python/migrate/asyncio_coroutine_to_async.py +0 -0
  44. {openrewrite_migrate_python-0.14.0.dev20260902170552 → openrewrite_migrate_python-0.14.0.dev20260903170551}/src/openrewrite_migrate_python/migrate/asyncio_deprecations.py +0 -0
  45. {openrewrite_migrate_python-0.14.0.dev20260902170552 → openrewrite_migrate_python-0.14.0.dev20260903170551}/src/openrewrite_migrate_python/migrate/avro_migrations.py +0 -0
  46. {openrewrite_migrate_python-0.14.0.dev20260902170552 → openrewrite_migrate_python-0.14.0.dev20260903170551}/src/openrewrite_migrate_python/migrate/calendar_deprecations.py +0 -0
  47. {openrewrite_migrate_python-0.14.0.dev20260902170552 → openrewrite_migrate_python-0.14.0.dev20260903170551}/src/openrewrite_migrate_python/migrate/cgi_migrations.py +0 -0
  48. {openrewrite_migrate_python-0.14.0.dev20260902170552 → openrewrite_migrate_python-0.14.0.dev20260903170551}/src/openrewrite_migrate_python/migrate/cgi_parse_deprecations.py +0 -0
  49. {openrewrite_migrate_python-0.14.0.dev20260902170552 → openrewrite_migrate_python-0.14.0.dev20260903170551}/src/openrewrite_migrate_python/migrate/collections_abc_migrations.py +0 -0
  50. {openrewrite_migrate_python-0.14.0.dev20260902170552 → openrewrite_migrate_python-0.14.0.dev20260903170551}/src/openrewrite_migrate_python/migrate/configparser_deprecations.py +0 -0
  51. {openrewrite_migrate_python-0.14.0.dev20260902170552 → openrewrite_migrate_python-0.14.0.dev20260903170551}/src/openrewrite_migrate_python/migrate/datetime_utc.py +0 -0
  52. {openrewrite_migrate_python-0.14.0.dev20260902170552 → openrewrite_migrate_python-0.14.0.dev20260903170551}/src/openrewrite_migrate_python/migrate/distutils_deprecations.py +0 -0
  53. {openrewrite_migrate_python-0.14.0.dev20260902170552 → openrewrite_migrate_python-0.14.0.dev20260903170551}/src/openrewrite_migrate_python/migrate/distutils_migrations.py +0 -0
  54. {openrewrite_migrate_python-0.14.0.dev20260902170552 → openrewrite_migrate_python-0.14.0.dev20260903170551}/src/openrewrite_migrate_python/migrate/functools_deprecations.py +0 -0
  55. {openrewrite_migrate_python-0.14.0.dev20260902170552 → openrewrite_migrate_python-0.14.0.dev20260903170551}/src/openrewrite_migrate_python/migrate/future_imports.py +0 -0
  56. {openrewrite_migrate_python-0.14.0.dev20260902170552 → openrewrite_migrate_python-0.14.0.dev20260903170551}/src/openrewrite_migrate_python/migrate/html_parser_deprecations.py +0 -0
  57. {openrewrite_migrate_python-0.14.0.dev20260902170552 → openrewrite_migrate_python-0.14.0.dev20260903170551}/src/openrewrite_migrate_python/migrate/imp_migrations.py +0 -0
  58. {openrewrite_migrate_python-0.14.0.dev20260902170552 → openrewrite_migrate_python-0.14.0.dev20260903170551}/src/openrewrite_migrate_python/migrate/langchain_classic_imports.py +0 -0
  59. {openrewrite_migrate_python-0.14.0.dev20260902170552 → openrewrite_migrate_python-0.14.0.dev20260903170551}/src/openrewrite_migrate_python/migrate/langchain_community_imports.py +0 -0
  60. {openrewrite_migrate_python-0.14.0.dev20260902170552 → openrewrite_migrate_python-0.14.0.dev20260903170551}/src/openrewrite_migrate_python/migrate/langchain_provider_imports.py +0 -0
  61. {openrewrite_migrate_python-0.14.0.dev20260902170552 → openrewrite_migrate_python-0.14.0.dev20260903170551}/src/openrewrite_migrate_python/migrate/macpath_deprecations.py +0 -0
  62. {openrewrite_migrate_python-0.14.0.dev20260902170552 → openrewrite_migrate_python-0.14.0.dev20260903170551}/src/openrewrite_migrate_python/migrate/mailcap_migrations.py +0 -0
  63. {openrewrite_migrate_python-0.14.0.dev20260902170552 → openrewrite_migrate_python-0.14.0.dev20260903170551}/src/openrewrite_migrate_python/migrate/nntplib_migrations.py +0 -0
  64. {openrewrite_migrate_python-0.14.0.dev20260902170552 → openrewrite_migrate_python-0.14.0.dev20260903170551}/src/openrewrite_migrate_python/migrate/os_deprecations.py +0 -0
  65. {openrewrite_migrate_python-0.14.0.dev20260902170552 → openrewrite_migrate_python-0.14.0.dev20260903170551}/src/openrewrite_migrate_python/migrate/pathlib_deprecations.py +0 -0
  66. {openrewrite_migrate_python-0.14.0.dev20260902170552 → openrewrite_migrate_python-0.14.0.dev20260903170551}/src/openrewrite_migrate_python/migrate/pep594_system_migrations.py +0 -0
  67. {openrewrite_migrate_python-0.14.0.dev20260902170552 → openrewrite_migrate_python-0.14.0.dev20260903170551}/src/openrewrite_migrate_python/migrate/pipes_migrations.py +0 -0
  68. {openrewrite_migrate_python-0.14.0.dev20260902170552 → openrewrite_migrate_python-0.14.0.dev20260903170551}/src/openrewrite_migrate_python/migrate/pkgutil_deprecations.py +0 -0
  69. {openrewrite_migrate_python-0.14.0.dev20260902170552 → openrewrite_migrate_python-0.14.0.dev20260903170551}/src/openrewrite_migrate_python/migrate/pydantic_deprecations.py +0 -0
  70. {openrewrite_migrate_python-0.14.0.dev20260902170552 → openrewrite_migrate_python-0.14.0.dev20260903170551}/src/openrewrite_migrate_python/migrate/pydantic_fields.py +0 -0
  71. {openrewrite_migrate_python-0.14.0.dev20260902170552 → openrewrite_migrate_python-0.14.0.dev20260903170551}/src/openrewrite_migrate_python/migrate/pydantic_model_fields.py +0 -0
  72. {openrewrite_migrate_python-0.14.0.dev20260902170552 → openrewrite_migrate_python-0.14.0.dev20260903170551}/src/openrewrite_migrate_python/migrate/re_deprecations.py +0 -0
  73. {openrewrite_migrate_python-0.14.0.dev20260902170552 → openrewrite_migrate_python-0.14.0.dev20260903170551}/src/openrewrite_migrate_python/migrate/removed_modules_312.py +0 -0
  74. {openrewrite_migrate_python-0.14.0.dev20260902170552 → openrewrite_migrate_python-0.14.0.dev20260903170551}/src/openrewrite_migrate_python/migrate/shutil_deprecations.py +0 -0
  75. {openrewrite_migrate_python-0.14.0.dev20260902170552 → openrewrite_migrate_python-0.14.0.dev20260903170551}/src/openrewrite_migrate_python/migrate/socket_deprecations.py +0 -0
  76. {openrewrite_migrate_python-0.14.0.dev20260902170552 → openrewrite_migrate_python-0.14.0.dev20260903170551}/src/openrewrite_migrate_python/migrate/string_formatting.py +0 -0
  77. {openrewrite_migrate_python-0.14.0.dev20260902170552 → openrewrite_migrate_python-0.14.0.dev20260903170551}/src/openrewrite_migrate_python/migrate/sys_deprecations.py +0 -0
  78. {openrewrite_migrate_python-0.14.0.dev20260902170552 → openrewrite_migrate_python-0.14.0.dev20260903170551}/src/openrewrite_migrate_python/migrate/sys_last_deprecations.py +0 -0
  79. {openrewrite_migrate_python-0.14.0.dev20260902170552 → openrewrite_migrate_python-0.14.0.dev20260903170551}/src/openrewrite_migrate_python/migrate/tarfile_deprecations.py +0 -0
  80. {openrewrite_migrate_python-0.14.0.dev20260902170552 → openrewrite_migrate_python-0.14.0.dev20260903170551}/src/openrewrite_migrate_python/migrate/telnetlib_migrations.py +0 -0
  81. {openrewrite_migrate_python-0.14.0.dev20260902170552 → openrewrite_migrate_python-0.14.0.dev20260903170551}/src/openrewrite_migrate_python/migrate/tempfile_deprecations.py +0 -0
  82. {openrewrite_migrate_python-0.14.0.dev20260902170552 → openrewrite_migrate_python-0.14.0.dev20260903170551}/src/openrewrite_migrate_python/migrate/threading_deprecations.py +0 -0
  83. {openrewrite_migrate_python-0.14.0.dev20260902170552 → openrewrite_migrate_python-0.14.0.dev20260903170551}/src/openrewrite_migrate_python/migrate/threading_is_alive_deprecation.py +0 -0
  84. {openrewrite_migrate_python-0.14.0.dev20260902170552 → openrewrite_migrate_python-0.14.0.dev20260903170551}/src/openrewrite_migrate_python/migrate/typing_callable.py +0 -0
  85. {openrewrite_migrate_python-0.14.0.dev20260902170552 → openrewrite_migrate_python-0.14.0.dev20260903170551}/src/openrewrite_migrate_python/migrate/typing_deprecations.py +0 -0
  86. {openrewrite_migrate_python-0.14.0.dev20260902170552 → openrewrite_migrate_python-0.14.0.dev20260903170551}/src/openrewrite_migrate_python/migrate/typing_union_to_pipe.py +0 -0
  87. {openrewrite_migrate_python-0.14.0.dev20260902170552 → openrewrite_migrate_python-0.14.0.dev20260903170551}/src/openrewrite_migrate_python/migrate/unittest_deprecations.py +0 -0
  88. {openrewrite_migrate_python-0.14.0.dev20260902170552 → openrewrite_migrate_python-0.14.0.dev20260903170551}/src/openrewrite_migrate_python/migrate/upgrade_to_langchain02.py +0 -0
  89. {openrewrite_migrate_python-0.14.0.dev20260902170552 → openrewrite_migrate_python-0.14.0.dev20260903170551}/src/openrewrite_migrate_python/migrate/upgrade_to_langchain1.py +0 -0
  90. {openrewrite_migrate_python-0.14.0.dev20260902170552 → openrewrite_migrate_python-0.14.0.dev20260903170551}/src/openrewrite_migrate_python/migrate/upgrade_to_pydantic.py +0 -0
  91. {openrewrite_migrate_python-0.14.0.dev20260902170552 → openrewrite_migrate_python-0.14.0.dev20260903170551}/src/openrewrite_migrate_python/migrate/upgrade_to_python310.py +0 -0
  92. {openrewrite_migrate_python-0.14.0.dev20260902170552 → openrewrite_migrate_python-0.14.0.dev20260903170551}/src/openrewrite_migrate_python/migrate/upgrade_to_python311.py +0 -0
  93. {openrewrite_migrate_python-0.14.0.dev20260902170552 → openrewrite_migrate_python-0.14.0.dev20260903170551}/src/openrewrite_migrate_python/migrate/upgrade_to_python312.py +0 -0
  94. {openrewrite_migrate_python-0.14.0.dev20260902170552 → openrewrite_migrate_python-0.14.0.dev20260903170551}/src/openrewrite_migrate_python/migrate/upgrade_to_python313.py +0 -0
  95. {openrewrite_migrate_python-0.14.0.dev20260902170552 → openrewrite_migrate_python-0.14.0.dev20260903170551}/src/openrewrite_migrate_python/migrate/upgrade_to_python314.py +0 -0
  96. {openrewrite_migrate_python-0.14.0.dev20260902170552 → openrewrite_migrate_python-0.14.0.dev20260903170551}/src/openrewrite_migrate_python/migrate/upgrade_to_python38.py +0 -0
  97. {openrewrite_migrate_python-0.14.0.dev20260902170552 → openrewrite_migrate_python-0.14.0.dev20260903170551}/src/openrewrite_migrate_python/migrate/upgrade_to_python39.py +0 -0
  98. {openrewrite_migrate_python-0.14.0.dev20260902170552 → openrewrite_migrate_python-0.14.0.dev20260903170551}/src/openrewrite_migrate_python/migrate/urllib_deprecations.py +0 -0
  99. {openrewrite_migrate_python-0.14.0.dev20260902170552 → openrewrite_migrate_python-0.14.0.dev20260903170551}/src/openrewrite_migrate_python/migrate/uu_migrations.py +0 -0
  100. {openrewrite_migrate_python-0.14.0.dev20260902170552 → openrewrite_migrate_python-0.14.0.dev20260903170551}/src/openrewrite_migrate_python/migrate/xdrlib_migrations.py +0 -0
  101. {openrewrite_migrate_python-0.14.0.dev20260902170552 → openrewrite_migrate_python-0.14.0.dev20260903170551}/src/openrewrite_migrate_python/migrate/xml_deprecations.py +0 -0
  102. {openrewrite_migrate_python-0.14.0.dev20260902170552 → openrewrite_migrate_python-0.14.0.dev20260903170551}/src/openrewrite_migrate_python.egg-info/dependency_links.txt +0 -0
  103. {openrewrite_migrate_python-0.14.0.dev20260902170552 → openrewrite_migrate_python-0.14.0.dev20260903170551}/src/openrewrite_migrate_python.egg-info/entry_points.txt +0 -0
  104. {openrewrite_migrate_python-0.14.0.dev20260902170552 → openrewrite_migrate_python-0.14.0.dev20260903170551}/src/openrewrite_migrate_python.egg-info/requires.txt +0 -0
  105. {openrewrite_migrate_python-0.14.0.dev20260902170552 → openrewrite_migrate_python-0.14.0.dev20260903170551}/src/openrewrite_migrate_python.egg-info/top_level.txt +0 -0
  106. {openrewrite_migrate_python-0.14.0.dev20260902170552 → openrewrite_migrate_python-0.14.0.dev20260903170551}/tests/test_aifc_migrations.py +0 -0
  107. {openrewrite_migrate_python-0.14.0.dev20260902170552 → openrewrite_migrate_python-0.14.0.dev20260903170551}/tests/test_array_deprecations.py +0 -0
  108. {openrewrite_migrate_python-0.14.0.dev20260902170552 → openrewrite_migrate_python-0.14.0.dev20260903170551}/tests/test_ast_deprecations.py +0 -0
  109. {openrewrite_migrate_python-0.14.0.dev20260902170552 → openrewrite_migrate_python-0.14.0.dev20260903170551}/tests/test_asyncio_coroutine_to_async.py +0 -0
  110. {openrewrite_migrate_python-0.14.0.dev20260902170552 → openrewrite_migrate_python-0.14.0.dev20260903170551}/tests/test_asyncio_deprecations.py +0 -0
  111. {openrewrite_migrate_python-0.14.0.dev20260902170552 → openrewrite_migrate_python-0.14.0.dev20260903170551}/tests/test_avro_migrations.py +0 -0
  112. {openrewrite_migrate_python-0.14.0.dev20260902170552 → openrewrite_migrate_python-0.14.0.dev20260903170551}/tests/test_calendar_deprecations.py +0 -0
  113. {openrewrite_migrate_python-0.14.0.dev20260902170552 → openrewrite_migrate_python-0.14.0.dev20260903170551}/tests/test_cgi_parse_deprecations.py +0 -0
  114. {openrewrite_migrate_python-0.14.0.dev20260902170552 → openrewrite_migrate_python-0.14.0.dev20260903170551}/tests/test_change_import_recipes.py +0 -0
  115. {openrewrite_migrate_python-0.14.0.dev20260902170552 → openrewrite_migrate_python-0.14.0.dev20260903170551}/tests/test_collections_abc_migrations.py +0 -0
  116. {openrewrite_migrate_python-0.14.0.dev20260902170552 → openrewrite_migrate_python-0.14.0.dev20260903170551}/tests/test_configparser_deprecations.py +0 -0
  117. {openrewrite_migrate_python-0.14.0.dev20260902170552 → openrewrite_migrate_python-0.14.0.dev20260903170551}/tests/test_datetime_utc.py +0 -0
  118. {openrewrite_migrate_python-0.14.0.dev20260902170552 → openrewrite_migrate_python-0.14.0.dev20260903170551}/tests/test_distutils_deprecations.py +0 -0
  119. {openrewrite_migrate_python-0.14.0.dev20260902170552 → openrewrite_migrate_python-0.14.0.dev20260903170551}/tests/test_future_imports.py +0 -0
  120. {openrewrite_migrate_python-0.14.0.dev20260902170552 → openrewrite_migrate_python-0.14.0.dev20260903170551}/tests/test_html_parser_deprecations.py +0 -0
  121. {openrewrite_migrate_python-0.14.0.dev20260902170552 → openrewrite_migrate_python-0.14.0.dev20260903170551}/tests/test_imp_migrations.py +0 -0
  122. {openrewrite_migrate_python-0.14.0.dev20260902170552 → openrewrite_migrate_python-0.14.0.dev20260903170551}/tests/test_langchain_classic_imports.py +0 -0
  123. {openrewrite_migrate_python-0.14.0.dev20260902170552 → openrewrite_migrate_python-0.14.0.dev20260903170551}/tests/test_langchain_community_imports.py +0 -0
  124. {openrewrite_migrate_python-0.14.0.dev20260902170552 → openrewrite_migrate_python-0.14.0.dev20260903170551}/tests/test_langchain_provider_imports.py +0 -0
  125. {openrewrite_migrate_python-0.14.0.dev20260902170552 → openrewrite_migrate_python-0.14.0.dev20260903170551}/tests/test_macpath_deprecations.py +0 -0
  126. {openrewrite_migrate_python-0.14.0.dev20260902170552 → openrewrite_migrate_python-0.14.0.dev20260903170551}/tests/test_os_deprecations.py +0 -0
  127. {openrewrite_migrate_python-0.14.0.dev20260902170552 → openrewrite_migrate_python-0.14.0.dev20260903170551}/tests/test_pep594_migrations.py +0 -0
  128. {openrewrite_migrate_python-0.14.0.dev20260902170552 → openrewrite_migrate_python-0.14.0.dev20260903170551}/tests/test_pep594_system_migrations.py +0 -0
  129. {openrewrite_migrate_python-0.14.0.dev20260902170552 → openrewrite_migrate_python-0.14.0.dev20260903170551}/tests/test_pkgutil_deprecations.py +0 -0
  130. {openrewrite_migrate_python-0.14.0.dev20260902170552 → openrewrite_migrate_python-0.14.0.dev20260903170551}/tests/test_pydantic_deprecations.py +0 -0
  131. {openrewrite_migrate_python-0.14.0.dev20260902170552 → openrewrite_migrate_python-0.14.0.dev20260903170551}/tests/test_pydantic_fields.py +0 -0
  132. {openrewrite_migrate_python-0.14.0.dev20260902170552 → openrewrite_migrate_python-0.14.0.dev20260903170551}/tests/test_pydantic_model_fields.py +0 -0
  133. {openrewrite_migrate_python-0.14.0.dev20260902170552 → openrewrite_migrate_python-0.14.0.dev20260903170551}/tests/test_re_deprecations.py +0 -0
  134. {openrewrite_migrate_python-0.14.0.dev20260902170552 → openrewrite_migrate_python-0.14.0.dev20260903170551}/tests/test_removed_modules_312.py +0 -0
  135. {openrewrite_migrate_python-0.14.0.dev20260902170552 → openrewrite_migrate_python-0.14.0.dev20260903170551}/tests/test_shutil_deprecations.py +0 -0
  136. {openrewrite_migrate_python-0.14.0.dev20260902170552 → openrewrite_migrate_python-0.14.0.dev20260903170551}/tests/test_string_formatting.py +0 -0
  137. {openrewrite_migrate_python-0.14.0.dev20260902170552 → openrewrite_migrate_python-0.14.0.dev20260903170551}/tests/test_sys_deprecations.py +0 -0
  138. {openrewrite_migrate_python-0.14.0.dev20260902170552 → openrewrite_migrate_python-0.14.0.dev20260903170551}/tests/test_sys_last_deprecations.py +0 -0
  139. {openrewrite_migrate_python-0.14.0.dev20260902170552 → openrewrite_migrate_python-0.14.0.dev20260903170551}/tests/test_tarfile_deprecations.py +0 -0
  140. {openrewrite_migrate_python-0.14.0.dev20260902170552 → openrewrite_migrate_python-0.14.0.dev20260903170551}/tests/test_threading_deprecations.py +0 -0
  141. {openrewrite_migrate_python-0.14.0.dev20260902170552 → openrewrite_migrate_python-0.14.0.dev20260903170551}/tests/test_threading_extended.py +0 -0
  142. {openrewrite_migrate_python-0.14.0.dev20260902170552 → openrewrite_migrate_python-0.14.0.dev20260903170551}/tests/test_threading_is_alive_deprecation.py +0 -0
  143. {openrewrite_migrate_python-0.14.0.dev20260902170552 → openrewrite_migrate_python-0.14.0.dev20260903170551}/tests/test_typing_alias_moves.py +0 -0
  144. {openrewrite_migrate_python-0.14.0.dev20260902170552 → openrewrite_migrate_python-0.14.0.dev20260903170551}/tests/test_typing_callable.py +0 -0
  145. {openrewrite_migrate_python-0.14.0.dev20260902170552 → openrewrite_migrate_python-0.14.0.dev20260903170551}/tests/test_typing_deprecations.py +0 -0
  146. {openrewrite_migrate_python-0.14.0.dev20260902170552 → openrewrite_migrate_python-0.14.0.dev20260903170551}/tests/test_typing_union_to_pipe.py +0 -0
  147. {openrewrite_migrate_python-0.14.0.dev20260902170552 → openrewrite_migrate_python-0.14.0.dev20260903170551}/tests/test_unittest_deprecations.py +0 -0
  148. {openrewrite_migrate_python-0.14.0.dev20260902170552 → openrewrite_migrate_python-0.14.0.dev20260903170551}/tests/test_upgrade_recipes.py +0 -0
  149. {openrewrite_migrate_python-0.14.0.dev20260902170552 → openrewrite_migrate_python-0.14.0.dev20260903170551}/tests/test_upgrade_to_pydantic.py +0 -0
  150. {openrewrite_migrate_python-0.14.0.dev20260902170552 → openrewrite_migrate_python-0.14.0.dev20260903170551}/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.dev20260902170552
3
+ Version: 0.14.0.dev20260903170551
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.dev20260902170552" # Updated dynamically during release
8
+ version = "0.14.0.dev20260903170551" # 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"
@@ -0,0 +1,57 @@
1
+ """Resolving a receiver-less call to the module member it was imported from."""
2
+
3
+ from typing import Dict, Optional
4
+
5
+ from rewrite import Cursor
6
+ from rewrite.java.tree import FieldAccess, Identifier, J, MethodInvocation
7
+ from rewrite.python.import_utils import get_alias_name, get_name_string, get_qualid_name
8
+ from rewrite.python.scope_utils import LocalBindings
9
+ from rewrite.python.tree import CompilationUnit, MultiImport
10
+
11
+
12
+ def _is_relative(from_: J) -> bool:
13
+ """Whether ``from_`` is dotted, which the LST spells as an empty leading identifier."""
14
+ while isinstance(from_, FieldAccess):
15
+ from_ = from_.target
16
+ return isinstance(from_, Identifier) and not from_.simple_name
17
+
18
+
19
+ class FromImports:
20
+ """The members of ``module`` a file binds with ``from <module> import <member>``.
21
+
22
+ Under this form the call has no receiver, and for a symbol the typeshed in
23
+ use omits, no resolved declaring type either. The releases that removed
24
+ these APIs span many versions, so no declared version resolves them all —
25
+ attribution quality does not make this fallback redundant.
26
+ """
27
+
28
+ def __init__(self, module: str) -> None:
29
+ self._module = module
30
+ self._members: Dict[str, str] = {}
31
+ self._locals = LocalBindings()
32
+
33
+ def scan(self, cu: CompilationUnit) -> None:
34
+ """Record the file's bindings; call from ``visit_compilation_unit``.
35
+
36
+ Top-level ``from`` statements only, since a guarded import's fallback may
37
+ bind the name to a shim rather than the module's own member.
38
+ """
39
+ self._members = {}
40
+ self._locals = LocalBindings()
41
+ for stmt in cu.statements:
42
+ if not isinstance(stmt, MultiImport) or stmt.from_ is None:
43
+ continue
44
+ # `from .locale import x` binds a sibling module, which
45
+ # `get_name_string` renders indistinguishably from the stdlib one.
46
+ if _is_relative(stmt.from_) or get_name_string(stmt.from_) != self._module:
47
+ continue
48
+ for imp in stmt.names:
49
+ name = get_qualid_name(imp.qualid)
50
+ self._members.setdefault(get_alias_name(imp) or name, name)
51
+
52
+ def member_called(self, method: MethodInvocation, cursor: Cursor) -> Optional[str]:
53
+ """The ``module`` member a receiver-less ``method`` calls, if it calls one."""
54
+ if method.select is not None or not isinstance(method.name, Identifier):
55
+ return None
56
+ name = method.name.simple_name
57
+ return None if self._locals.is_bound(cursor, name) else self._members.get(name)
@@ -18,9 +18,14 @@ from rewrite import ExecutionContext, Preconditions, Recipe, TreeVisitor
18
18
  from rewrite.category import CategoryDescriptor
19
19
  from rewrite.decorators import categorize
20
20
  from rewrite.marketplace import Python
21
+ from rewrite.python.add_import import AddImportOptions, maybe_add_import
21
22
  from rewrite.python.preconditions import uses_import
23
+ from rewrite.python.remove_import import RemoveImportOptions, maybe_remove_import
24
+ from rewrite.python.tree import CompilationUnit
22
25
  from rewrite.python.visitor import PythonVisitor
23
- from rewrite.java.tree import Identifier, MethodInvocation
26
+ from rewrite.java.tree import Identifier, J, MethodInvocation
27
+
28
+ from ._from_imports import FromImports
24
29
 
25
30
  # Define category path: Python > Migrate > Python 3.11
26
31
  _Python311 = [
@@ -105,6 +110,14 @@ class ReplaceGettextDeprecations(Recipe):
105
110
 
106
111
  def editor(self) -> TreeVisitor[Any, ExecutionContext]:
107
112
  class Visitor(PythonVisitor[ExecutionContext]):
113
+ def __init__(self) -> None:
114
+ super().__init__()
115
+ self._imports = FromImports("gettext")
116
+
117
+ def visit_compilation_unit(self, cu: CompilationUnit, p: ExecutionContext) -> J:
118
+ self._imports.scan(cu)
119
+ return super().visit_compilation_unit(cu, p)
120
+
108
121
  def visit_method_invocation(
109
122
  self, method: MethodInvocation, p: ExecutionContext
110
123
  ) -> Optional[MethodInvocation]:
@@ -115,12 +128,21 @@ class ReplaceGettextDeprecations(Recipe):
115
128
 
116
129
  method_name = method.name.simple_name
117
130
 
118
- # Check if this is a deprecated gettext function
119
- if method_name in GETTEXT_DEPRECATIONS:
131
+ # A receiver-less call belongs to the branch below, which moves
132
+ # the import as well as renaming the call.
133
+ if method.select is not None and method_name in GETTEXT_DEPRECATIONS:
120
134
  if _is_gettext_method(method, method_name):
121
135
  new_name = GETTEXT_DEPRECATIONS[method_name]
122
136
  return _rename_method(method, new_name)
123
137
 
124
- return method
138
+ # `from gettext import lgettext` names the function itself, so
139
+ # the import moves to the replacement along with the call.
140
+ member = self._imports.member_called(method, self.cursor)
141
+ new_name = GETTEXT_DEPRECATIONS.get(member) if member else None
142
+ if new_name is None:
143
+ return method
144
+ maybe_add_import(self, AddImportOptions(module="gettext", name=new_name))
145
+ maybe_remove_import(self, RemoveImportOptions(module="gettext", name=member))
146
+ return _rename_method(method, new_name)
125
147
 
126
148
  return Preconditions.check(uses_import("gettext"), Visitor())
@@ -14,12 +14,18 @@ from rewrite.category import CategoryDescriptor
14
14
  from rewrite.decorators import categorize
15
15
  from rewrite.marketplace import Python
16
16
  from rewrite.markers import Markers
17
+ from rewrite.python.add_import import AddImportOptions, maybe_add_import
18
+ from rewrite.python.import_utils import get_name_string
17
19
  from rewrite.python.preconditions import uses_import
20
+ from rewrite.python.remove_import import RemoveImportOptions, maybe_remove_import
21
+ from rewrite.python.tree import CompilationUnit
18
22
  from rewrite.python.visitor import PythonVisitor
19
- from rewrite.java.tree import Identifier, MethodInvocation, Literal
23
+ from rewrite.java.tree import Identifier, J, MethodInvocation, Literal
20
24
  from rewrite.java.support_types import JRightPadded, Space
21
25
  from rewrite.utils import random_id
22
26
 
27
+ from ._from_imports import FromImports
28
+
23
29
  # Define category path: Python > Migrate > Python 3.11
24
30
  _Python311 = [
25
31
  *Python,
@@ -142,21 +148,40 @@ class ReplaceLocaleResetlocale(Recipe):
142
148
 
143
149
  def editor(self) -> TreeVisitor[Any, ExecutionContext]:
144
150
  class Visitor(PythonVisitor[ExecutionContext]):
151
+ def __init__(self) -> None:
152
+ super().__init__()
153
+ self._imports = FromImports("locale")
154
+
155
+ def visit_compilation_unit(self, cu: CompilationUnit, p: ExecutionContext) -> J:
156
+ self._imports.scan(cu)
157
+ return super().visit_compilation_unit(cu, p)
158
+
145
159
  def visit_method_invocation(
146
160
  self, method: MethodInvocation, p: ExecutionContext
147
161
  ) -> Optional[MethodInvocation]:
148
162
  method = super().visit_method_invocation(method, p)
149
163
 
150
- if _is_locale_method(method, "resetlocale"):
151
- # Rename resetlocale -> setlocale
164
+ select = method.select
165
+ if select is not None and _is_locale_method(method, "resetlocale"):
152
166
  method = _rename_method(method, "setlocale")
153
- # Set arguments to (locale.LC_ALL, "")
154
- method = _set_arguments(
167
+ # LC_ALL is reached through the same name the call reached
168
+ # the module by, which `import locale as loc` makes `loc`.
169
+ return _set_arguments(
155
170
  method,
156
- ("id", "locale.LC_ALL"),
157
- ("str", "")
171
+ ("id", f"{get_name_string(select)}.LC_ALL"),
172
+ ("str", ""),
158
173
  )
159
- return method
174
+
175
+ if self._imports.member_called(method, self.cursor) == "resetlocale":
176
+ # `setlocale` and `LC_ALL` are spelled unqualified, so each
177
+ # needs an import of its own.
178
+ for name in ("setlocale", "LC_ALL"):
179
+ maybe_add_import(self, AddImportOptions(module="locale", name=name))
180
+ maybe_remove_import(
181
+ self, RemoveImportOptions(module="locale", name="resetlocale")
182
+ )
183
+ method = _rename_method(method, "setlocale")
184
+ return _set_arguments(method, ("id", "LC_ALL"), ("str", ""))
160
185
 
161
186
  return method
162
187
 
@@ -13,9 +13,10 @@ 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
 
21
22
  # Define category path: Python > Migrate > Python 3.11
@@ -25,6 +26,11 @@ _Python311 = [
25
26
  CategoryDescriptor(display_name="Python 3.11"),
26
27
  ]
27
28
 
29
+ # One pattern covers `import locale`, `import locale as loc` and the from-import
30
+ # form, since the owner resolves the same for each. Once the scheduled removal
31
+ # lands this needs the `_from_imports` fallback the sibling recipes carry.
32
+ _GETDEFAULTLOCALE = MethodMatcher.create("locale getdefaultlocale(..)")
33
+
28
34
 
29
35
  @categorize(_Python311)
30
36
  class FindLocaleGetdefaultlocale(Recipe):
@@ -73,15 +79,7 @@ class FindLocaleGetdefaultlocale(Recipe):
73
79
  ) -> Optional[MethodInvocation]:
74
80
  method = super().visit_method_invocation(method, p)
75
81
 
76
- if not isinstance(method.name, Identifier):
77
- return method
78
- if method.name.simple_name != "getdefaultlocale":
79
- return method
80
-
81
- select = method.select
82
- if not isinstance(select, Identifier):
83
- return method
84
- if select.simple_name != "locale":
82
+ if not _GETDEFAULTLOCALE.matches(method):
85
83
  return method
86
84
 
87
85
  return mark_deprecated(
@@ -14,15 +14,17 @@ from rewrite.category import CategoryDescriptor
14
14
  from rewrite.decorators import categorize
15
15
  from rewrite.marketplace import Python
16
16
  from rewrite.markers import Markers
17
- from rewrite.python.preconditions import uses_method
17
+ from rewrite.python.preconditions import uses_import
18
18
  from rewrite.python.visitor import PythonVisitor
19
19
 
20
20
  from rewrite.python.type_utils import is_of_class_type
21
21
  from rewrite.java.support_types import JLeftPadded, JRightPadded, Space
22
- from rewrite.java.tree import Identifier, Literal, MethodInvocation
23
- from rewrite.python.tree import NamedArgument
22
+ from rewrite.java.tree import Identifier, J, MethodInvocation
23
+ from rewrite.python.tree import CompilationUnit, NamedArgument
24
24
  from rewrite.utils import random_id
25
25
 
26
+ from ._from_imports import FromImports
27
+
26
28
  # Define category path: Python > Migrate > Python 3.8
27
29
  _Python38 = [
28
30
  *Python,
@@ -31,6 +33,22 @@ _Python38 = [
31
33
  ]
32
34
 
33
35
 
36
+ def _qualify(method: MethodInvocation, module: str) -> MethodInvocation:
37
+ """``method`` called through ``module`` as its receiver."""
38
+ select = Identifier(
39
+ _id=random_id(),
40
+ _prefix=Space.EMPTY,
41
+ _markers=Markers.EMPTY,
42
+ _annotations=[],
43
+ _simple_name=module,
44
+ _type=None,
45
+ _field_type=None,
46
+ )
47
+ return method.padding.replace(
48
+ _select=JRightPadded(select, Space.EMPTY, Markers.EMPTY)
49
+ )
50
+
51
+
34
52
  @categorize(_Python38)
35
53
  class ReplacePlatformPopen(Recipe):
36
54
  """
@@ -70,6 +88,14 @@ class ReplacePlatformPopen(Recipe):
70
88
 
71
89
  def editor(self) -> TreeVisitor[Any, ExecutionContext]:
72
90
  class Visitor(PythonVisitor[ExecutionContext]):
91
+ def __init__(self) -> None:
92
+ super().__init__()
93
+ self._imports = FromImports("platform")
94
+
95
+ def visit_compilation_unit(self, cu: CompilationUnit, p: ExecutionContext) -> J:
96
+ self._imports.scan(cu)
97
+ return super().visit_compilation_unit(cu, p)
98
+
73
99
  def visit_method_invocation(
74
100
  self, method: MethodInvocation, p: ExecutionContext
75
101
  ) -> Optional[MethodInvocation]:
@@ -77,23 +103,26 @@ class ReplacePlatformPopen(Recipe):
77
103
 
78
104
  if not isinstance(method.name, Identifier):
79
105
  return method
80
- if method.name.simple_name != "popen":
81
- return method
82
106
 
83
107
  select = method.select
84
- if not isinstance(select, Identifier):
108
+ if select is None:
109
+ if self._imports.member_called(method, self.cursor) != "popen":
110
+ return method
111
+ method = _qualify(method, "subprocess")
112
+ elif (
113
+ method.name.simple_name == "popen"
114
+ and isinstance(select, Identifier)
115
+ # Confirm the receiver resolves to the `platform` module (by
116
+ # type, so an aliased import works and a same-named variable is
117
+ # not rewritten into a destructive `subprocess.check_output`).
118
+ and is_of_class_type(select.type, "platform")
119
+ ):
120
+ new_select = select.replace(_simple_name="subprocess")
121
+ old_padded_select = method.padding.select
122
+ new_padded_select = old_padded_select.replace(_element=new_select)
123
+ method = method.padding.replace(_select=new_padded_select)
124
+ else:
85
125
  return method
86
- # Confirm the receiver resolves to the `platform` module (by
87
- # type, so an aliased import works and a same-named variable is
88
- # not rewritten into a destructive `subprocess.check_output`).
89
- if not is_of_class_type(select.type, "platform"):
90
- return method
91
-
92
- # Replace platform with subprocess
93
- new_select = select.replace(_simple_name="subprocess")
94
- old_padded_select = method.padding.select
95
- new_padded_select = old_padded_select.replace(_element=new_select)
96
- method = method.padding.replace(_select=new_padded_select)
97
126
 
98
127
  # Rename popen -> check_output
99
128
  new_name = method.name.replace(_simple_name="check_output")
@@ -141,4 +170,4 @@ class ReplacePlatformPopen(Recipe):
141
170
 
142
171
  return method
143
172
 
144
- return Preconditions.check(uses_method("*..* popen(..)"), Visitor())
173
+ return Preconditions.check(uses_import("platform"), Visitor())
@@ -15,8 +15,10 @@ from rewrite.category import CategoryDescriptor
15
15
  from rewrite.decorators import categorize
16
16
  from rewrite.marketplace import Python
17
17
  from rewrite.python.preconditions import uses_import
18
+ from rewrite.python.tree import CompilationUnit
18
19
  from rewrite.python.visitor import PythonVisitor
19
- from rewrite.java.tree import Identifier, MethodInvocation
20
+ from rewrite.java.tree import Identifier, J, MethodInvocation
21
+ from ._from_imports import FromImports
20
22
  from ._markers import mark_deprecated
21
23
 
22
24
  # Define category path: Python > Migrate > Python 3.12
@@ -85,12 +87,21 @@ class FindSslMatchHostname(Recipe):
85
87
 
86
88
  def editor(self) -> TreeVisitor[Any, ExecutionContext]:
87
89
  class Visitor(PythonVisitor[ExecutionContext]):
90
+ def __init__(self) -> None:
91
+ super().__init__()
92
+ self._imports = FromImports("ssl")
93
+
94
+ def visit_compilation_unit(self, cu: CompilationUnit, p: ExecutionContext) -> J:
95
+ self._imports.scan(cu)
96
+ return super().visit_compilation_unit(cu, p)
97
+
88
98
  def visit_method_invocation(
89
99
  self, method: MethodInvocation, p: ExecutionContext
90
100
  ) -> Optional[MethodInvocation]:
91
101
  method = super().visit_method_invocation(method, p)
92
102
 
93
- if _is_ssl_method(method, "match_hostname"):
103
+ if (_is_ssl_method(method, "match_hostname")
104
+ or self._imports.member_called(method, self.cursor) == "match_hostname"):
94
105
  return mark_deprecated(
95
106
  method,
96
107
  "ssl.match_hostname() is deprecated",
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: openrewrite-migrate-python
3
- Version: 0.14.0.dev20260902170552
3
+ Version: 0.14.0.dev20260903170551
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
@@ -22,6 +22,7 @@ src/openrewrite_migrate_python.egg-info/entry_points.txt
22
22
  src/openrewrite_migrate_python.egg-info/requires.txt
23
23
  src/openrewrite_migrate_python.egg-info/top_level.txt
24
24
  src/openrewrite_migrate_python/migrate/__init__.py
25
+ src/openrewrite_migrate_python/migrate/_from_imports.py
25
26
  src/openrewrite_migrate_python/migrate/_import_hygiene.py
26
27
  src/openrewrite_migrate_python/migrate/_langchain_tables.py
27
28
  src/openrewrite_migrate_python/migrate/_markers.py
@@ -57,6 +57,22 @@ class TestReplaceGettextDeprecations:
57
57
  )
58
58
  )
59
59
 
60
+ def test_replaces_from_import_form(self):
61
+ """The call and the import both move off the removed name."""
62
+ spec = RecipeSpec(recipe=ReplaceGettextDeprecations())
63
+ spec.rewrite_run(
64
+ python(
65
+ """
66
+ from gettext import lgettext
67
+ msg = lgettext("Hello")
68
+ """,
69
+ """
70
+ from gettext import gettext
71
+ msg = gettext("Hello")
72
+ """,
73
+ )
74
+ )
75
+
60
76
  def test_no_change_when_already_correct(self):
61
77
  """Test that already-correct functions are not changed."""
62
78
  spec = RecipeSpec(recipe=ReplaceGettextDeprecations())
@@ -0,0 +1,110 @@
1
+ """Tests for locale deprecation migration recipes."""
2
+
3
+ from rewrite.test import RecipeSpec, python
4
+ from openrewrite_migrate_python.migrate.locale_deprecations import (
5
+ ReplaceLocaleResetlocale,
6
+ )
7
+
8
+ class TestReplaceLocaleResetlocale:
9
+ """Tests for the ReplaceLocaleResetlocale recipe."""
10
+
11
+ def test_replaces_locale_resetlocale(self):
12
+ """Test that locale.resetlocale() is replaced with setlocale."""
13
+ spec = RecipeSpec(recipe=ReplaceLocaleResetlocale())
14
+ spec.rewrite_run(
15
+ python(
16
+ """
17
+ import locale
18
+ locale.resetlocale()
19
+ """,
20
+ """
21
+ import locale
22
+ locale.setlocale(locale.LC_ALL, "")
23
+ """,
24
+ )
25
+ )
26
+
27
+ def test_replacement_follows_the_import_form(self):
28
+ """`setlocale` and `LC_ALL` are spelled the way the file reaches `locale`."""
29
+ spec = RecipeSpec(recipe=ReplaceLocaleResetlocale())
30
+ spec.rewrite_run(
31
+ python(
32
+ """
33
+ from locale import resetlocale
34
+ resetlocale()
35
+ """,
36
+ """
37
+ from locale import LC_ALL, setlocale
38
+ setlocale(LC_ALL, "")
39
+ """,
40
+ )
41
+ )
42
+
43
+ spec.rewrite_run(
44
+ python(
45
+ """
46
+ import locale as loc
47
+ loc.resetlocale()
48
+ """,
49
+ """
50
+ import locale as loc
51
+ loc.setlocale(loc.LC_ALL, "")
52
+ """,
53
+ )
54
+ )
55
+
56
+ def test_no_change_when_setlocale(self):
57
+ """Test that locale.setlocale() is not marked."""
58
+ spec = RecipeSpec(recipe=ReplaceLocaleResetlocale())
59
+ spec.rewrite_run(
60
+ python(
61
+ """
62
+ import locale
63
+ locale.setlocale(locale.LC_ALL, "")
64
+ """
65
+ )
66
+ )
67
+
68
+ def test_no_change_when_locally_shadowed(self):
69
+ """A local `resetlocale` is not the module's, however the module is imported."""
70
+ spec = RecipeSpec(recipe=ReplaceLocaleResetlocale())
71
+ spec.rewrite_run(
72
+ python(
73
+ """
74
+ from locale import resetlocale
75
+
76
+ def reset():
77
+ def resetlocale():
78
+ pass
79
+ resetlocale()
80
+ """
81
+ )
82
+ )
83
+
84
+ def test_no_change_on_a_relative_import(self):
85
+ """`from .locale import` binds a sibling module, not the stdlib one."""
86
+ spec = RecipeSpec(recipe=ReplaceLocaleResetlocale())
87
+ spec.rewrite_run(
88
+ python(
89
+ """
90
+ from .locale import resetlocale
91
+ resetlocale()
92
+ """
93
+ )
94
+ )
95
+
96
+ def test_no_change_when_different_module(self):
97
+ """Test that resetlocale on a different object is not marked."""
98
+ spec = RecipeSpec(recipe=ReplaceLocaleResetlocale())
99
+ spec.rewrite_run(
100
+ python(
101
+ """
102
+ class MyLocale:
103
+ def resetlocale(self):
104
+ pass
105
+
106
+ obj = MyLocale()
107
+ obj.resetlocale()
108
+ """
109
+ )
110
+ )
@@ -0,0 +1,45 @@
1
+ """Tests for locale.getdefaultlocale() deprecation recipe."""
2
+
3
+ from rewrite.test import RecipeSpec, python
4
+
5
+ from openrewrite_migrate_python.migrate.locale_getdefaultlocale_deprecation import (
6
+ FindLocaleGetdefaultlocale,
7
+ )
8
+
9
+ _MARKER = "/*~~(locale.getdefaultlocale() was deprecated in Python 3.11. Use locale.setlocale(), locale.getlocale(), or locale.getpreferredencoding(False) instead.)~~>*/"
10
+
11
+
12
+ class TestFindLocaleGetdefaultlocale:
13
+ """Tests for FindLocaleGetdefaultlocale recipe."""
14
+
15
+ def test_finds_locale_getdefaultlocale(self):
16
+ spec = RecipeSpec(recipe=FindLocaleGetdefaultlocale())
17
+ spec.rewrite_run(
18
+ python(
19
+ "import locale\nlang, enc = locale.getdefaultlocale()",
20
+ f"import locale\nlang, enc = {_MARKER}locale.getdefaultlocale()",
21
+ )
22
+ )
23
+
24
+ def test_finds_from_import_and_aliased_forms(self):
25
+ """The import form does not decide whether the call is `locale`'s."""
26
+ spec = RecipeSpec(recipe=FindLocaleGetdefaultlocale())
27
+ spec.rewrite_run(
28
+ python(
29
+ "from locale import getdefaultlocale\nlang, enc = getdefaultlocale()",
30
+ f"from locale import getdefaultlocale\nlang, enc = {_MARKER}getdefaultlocale()",
31
+ )
32
+ )
33
+
34
+ spec.rewrite_run(
35
+ python(
36
+ "import locale as loc\nlang, enc = loc.getdefaultlocale()",
37
+ f"import locale as loc\nlang, enc = {_MARKER}loc.getdefaultlocale()",
38
+ )
39
+ )
40
+
41
+ def test_no_change_when_using_getlocale(self):
42
+ spec = RecipeSpec(recipe=FindLocaleGetdefaultlocale())
43
+ spec.rewrite_run(
44
+ python("import locale\nlang, enc = locale.getlocale()")
45
+ )
@@ -25,40 +25,60 @@ class TestReplacePlatformPopen:
25
25
  )
26
26
  )
27
27
 
28
- def test_no_change_when_not_platform_popen(self):
28
+ def test_replaces_from_import_form(self):
29
+ """A receiver-less call bound by `from platform import popen` is rewritten."""
29
30
  spec = RecipeSpec(recipe=ReplacePlatformPopen())
30
31
  spec.rewrite_run(
31
32
  python(
32
33
  """
33
- import os
34
- output = os.popen('ls').read()
34
+ from platform import popen
35
+ output = popen('ls')
36
+ """,
37
+ """
38
+ from platform import popen
39
+ output = subprocess.check_output('ls', shell=True)
40
+ """,
41
+ )
42
+ )
43
+
44
+ def test_no_change_on_another_platform_function(self):
45
+ """`popen` is the only function of the module this recipe rewrites."""
46
+ spec = RecipeSpec(recipe=ReplacePlatformPopen())
47
+ spec.rewrite_run(
48
+ python(
49
+ """
50
+ import platform
51
+ name = platform.system()
35
52
  """
36
53
  )
37
54
  )
38
55
 
39
56
  def test_no_change_when_already_subprocess(self):
57
+ """Re-running over this recipe's own output leaves it alone."""
40
58
  spec = RecipeSpec(recipe=ReplacePlatformPopen())
41
59
  spec.rewrite_run(
42
60
  python(
43
61
  """
44
- import subprocess
62
+ import platform
45
63
  output = subprocess.check_output('ls', shell=True)
46
64
  """
47
65
  )
48
66
  )
49
67
 
50
- def test_no_change_on_variable_named_platform(self):
51
- """A local variable named `platform` that isn't the module is left untouched."""
68
+ def test_no_change_on_another_objects_popen(self):
69
+ """`popen` on something that isn't the module, in a file that imports it."""
52
70
  spec = RecipeSpec(recipe=ReplacePlatformPopen())
53
71
  spec.rewrite_run(
54
72
  python(
55
73
  """
74
+ import platform
75
+
56
76
  class Shell:
57
77
  def popen(self, cmd):
58
78
  return cmd
59
79
 
60
- platform = Shell()
61
- output = platform.popen('ls')
80
+ shell = Shell()
81
+ output = shell.popen('ls')
62
82
  """
63
83
  )
64
84
  )