openrewrite-migrate-python 0.17.0.dev20261021175539__tar.gz → 0.17.0.dev20261022150922__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 (212) hide show
  1. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/PKG-INFO +1 -1
  2. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/pyproject.toml +1 -1
  3. openrewrite_migrate_python-0.17.0.dev20261022150922/src/openrewrite_migrate_python/migrate/cgi_escape_deprecations.py +186 -0
  4. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/src/openrewrite_migrate_python/migrate/cgi_parse_deprecations.py +1 -1
  5. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/src/openrewrite_migrate_python/migrate/string_formatting.py +12 -2
  6. openrewrite_migrate_python-0.17.0.dev20261022150922/src/openrewrite_migrate_python/migrate/sys_last_deprecations.py +227 -0
  7. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/src/openrewrite_migrate_python/migrate/upgrade_to_python38.py +7 -6
  8. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/src/openrewrite_migrate_python.egg-info/PKG-INFO +1 -1
  9. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/src/openrewrite_migrate_python.egg-info/SOURCES.txt +2 -0
  10. openrewrite_migrate_python-0.17.0.dev20261022150922/tests/test_cgi_escape_deprecations.py +236 -0
  11. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/tests/test_change_import_recipes.py +0 -12
  12. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/tests/test_string_formatting.py +75 -8
  13. openrewrite_migrate_python-0.17.0.dev20261022150922/tests/test_sys_last_deprecations.py +286 -0
  14. openrewrite_migrate_python-0.17.0.dev20261021175539/src/openrewrite_migrate_python/migrate/sys_last_deprecations.py +0 -141
  15. openrewrite_migrate_python-0.17.0.dev20261021175539/tests/test_sys_last_deprecations.py +0 -142
  16. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/setup.cfg +0 -0
  17. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/src/openrewrite_code_quality_python/__init__.py +0 -0
  18. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/src/openrewrite_code_quality_python/cleanup/__init__.py +0 -0
  19. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/src/openrewrite_code_quality_python/cleanup/_literals.py +0 -0
  20. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/src/openrewrite_code_quality_python/cleanup/_negation.py +0 -0
  21. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/src/openrewrite_code_quality_python/cleanup/assign_return.py +0 -0
  22. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/src/openrewrite_code_quality_python/cleanup/attr_access.py +0 -0
  23. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/src/openrewrite_code_quality_python/cleanup/boolean_simplification.py +0 -0
  24. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/src/openrewrite_code_quality_python/cleanup/collection_literals.py +0 -0
  25. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/src/openrewrite_code_quality_python/cleanup/comparison_simplification.py +0 -0
  26. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/src/openrewrite_code_quality_python/cleanup/complex_transforms.py +0 -0
  27. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/src/openrewrite_code_quality_python/cleanup/comprehension_cleanup.py +0 -0
  28. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/src/openrewrite_code_quality_python/cleanup/conditionals.py +0 -0
  29. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/src/openrewrite_code_quality_python/cleanup/datetime_cleanup.py +0 -0
  30. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/src/openrewrite_code_quality_python/cleanup/dict_cleanup.py +0 -0
  31. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/src/openrewrite_code_quality_python/cleanup/exception_cleanup.py +0 -0
  32. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/src/openrewrite_code_quality_python/cleanup/expression_simplification.py +0 -0
  33. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/src/openrewrite_code_quality_python/cleanup/logger_warn.py +0 -0
  34. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/src/openrewrite_code_quality_python/cleanup/loop_cleanup.py +0 -0
  35. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/src/openrewrite_code_quality_python/cleanup/merge_nested_with.py +0 -0
  36. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/src/openrewrite_code_quality_python/cleanup/merge_startswith_endswith.py +0 -0
  37. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/src/openrewrite_code_quality_python/cleanup/naming_conventions.py +0 -0
  38. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/src/openrewrite_code_quality_python/cleanup/negated_operators.py +0 -0
  39. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/src/openrewrite_code_quality_python/cleanup/none_and_identity.py +0 -0
  40. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/src/openrewrite_code_quality_python/cleanup/object_inheritance.py +0 -0
  41. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/src/openrewrite_code_quality_python/cleanup/pandas_cleanup.py +0 -0
  42. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/src/openrewrite_code_quality_python/cleanup/python_best_practices.py +0 -0
  43. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/src/openrewrite_code_quality_python/cleanup/range_cleanup.py +0 -0
  44. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/src/openrewrite_code_quality_python/cleanup/redundant_code.py +0 -0
  45. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/src/openrewrite_code_quality_python/cleanup/remove_trailing_return_none.py +0 -0
  46. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/src/openrewrite_code_quality_python/cleanup/string_cleanup.py +0 -0
  47. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/src/openrewrite_code_quality_python/cleanup/unreachable_code.py +0 -0
  48. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/src/openrewrite_code_quality_python/cleanup/use_items.py +0 -0
  49. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/src/openrewrite_code_quality_python/cleanup/use_list_clear.py +0 -0
  50. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/src/openrewrite_code_quality_python/cleanup/yoda_conditions.py +0 -0
  51. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/src/openrewrite_code_quality_python/codequality/__init__.py +0 -0
  52. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/src/openrewrite_code_quality_python/codequality/_reindent.py +0 -0
  53. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/src/openrewrite_code_quality_python/codequality/_semantically_equal.py +0 -0
  54. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/src/openrewrite_code_quality_python/codequality/_side_effects.py +0 -0
  55. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/src/openrewrite_code_quality_python/codequality/_trivia.py +0 -0
  56. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/src/openrewrite_code_quality_python/codequality/_truth_value.py +0 -0
  57. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/src/openrewrite_code_quality_python/codequality/all_branches_identical.py +0 -0
  58. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/src/openrewrite_code_quality_python/codequality/boolean_checks_not_inverted.py +0 -0
  59. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/src/openrewrite_code_quality_python/codequality/code_quality.py +0 -0
  60. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/src/openrewrite_code_quality_python/codequality/collapsible_if_statements.py +0 -0
  61. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/src/openrewrite_code_quality_python/codequality/find_suspicious_chained_comparison.py +0 -0
  62. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/src/openrewrite_code_quality_python/codequality/merge_identical_branches.py +0 -0
  63. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/src/openrewrite_code_quality_python/codequality/remove_duplicate_conditions.py +0 -0
  64. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/src/openrewrite_code_quality_python/codequality/remove_self_assignment.py +0 -0
  65. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/src/openrewrite_code_quality_python/codequality/remove_unconditional_value_overwrite.py +0 -0
  66. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/src/openrewrite_code_quality_python/codequality/simplify_boolean_literal.py +0 -0
  67. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/src/openrewrite_code_quality_python/codequality/simplify_redundant_logical_expression.py +0 -0
  68. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/src/openrewrite_migrate_python/__init__.py +0 -0
  69. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/src/openrewrite_migrate_python/migrate/__init__.py +0 -0
  70. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/src/openrewrite_migrate_python/migrate/_decorators.py +0 -0
  71. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/src/openrewrite_migrate_python/migrate/_langchain_tables.py +0 -0
  72. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/src/openrewrite_migrate_python/migrate/_markers.py +0 -0
  73. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/src/openrewrite_migrate_python/migrate/_method_renames.py +0 -0
  74. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/src/openrewrite_migrate_python/migrate/_module_imports.py +0 -0
  75. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/src/openrewrite_migrate_python/migrate/_slots.py +0 -0
  76. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/src/openrewrite_migrate_python/migrate/aifc_migrations.py +0 -0
  77. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/src/openrewrite_migrate_python/migrate/array_deprecations.py +0 -0
  78. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/src/openrewrite_migrate_python/migrate/ast_deprecations.py +0 -0
  79. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/src/openrewrite_migrate_python/migrate/asyncio_coroutine_to_async.py +0 -0
  80. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/src/openrewrite_migrate_python/migrate/asyncio_deprecations.py +0 -0
  81. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/src/openrewrite_migrate_python/migrate/avro_migrations.py +0 -0
  82. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/src/openrewrite_migrate_python/migrate/backoff_to_tenacity.py +0 -0
  83. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/src/openrewrite_migrate_python/migrate/calendar_deprecations.py +0 -0
  84. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/src/openrewrite_migrate_python/migrate/cgi_migrations.py +0 -0
  85. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/src/openrewrite_migrate_python/migrate/collections_abc_migrations.py +0 -0
  86. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/src/openrewrite_migrate_python/migrate/configparser_deprecations.py +0 -0
  87. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/src/openrewrite_migrate_python/migrate/datetime_utc.py +0 -0
  88. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/src/openrewrite_migrate_python/migrate/distutils_deprecations.py +0 -0
  89. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/src/openrewrite_migrate_python/migrate/distutils_migrations.py +0 -0
  90. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/src/openrewrite_migrate_python/migrate/functools_deprecations.py +0 -0
  91. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/src/openrewrite_migrate_python/migrate/future_imports.py +0 -0
  92. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/src/openrewrite_migrate_python/migrate/gettext_deprecations.py +0 -0
  93. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/src/openrewrite_migrate_python/migrate/glob_deprecations.py +0 -0
  94. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/src/openrewrite_migrate_python/migrate/html_parser_deprecations.py +0 -0
  95. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/src/openrewrite_migrate_python/migrate/imp_migrations.py +0 -0
  96. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/src/openrewrite_migrate_python/migrate/importlib_resources_deprecations.py +0 -0
  97. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/src/openrewrite_migrate_python/migrate/inspect_deprecations.py +0 -0
  98. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/src/openrewrite_migrate_python/migrate/langchain_classic_imports.py +0 -0
  99. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/src/openrewrite_migrate_python/migrate/langchain_community_imports.py +0 -0
  100. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/src/openrewrite_migrate_python/migrate/langchain_provider_imports.py +0 -0
  101. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/src/openrewrite_migrate_python/migrate/locale_deprecations.py +0 -0
  102. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/src/openrewrite_migrate_python/migrate/locale_getdefaultlocale_deprecation.py +0 -0
  103. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/src/openrewrite_migrate_python/migrate/macpath_deprecations.py +0 -0
  104. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/src/openrewrite_migrate_python/migrate/mailcap_migrations.py +0 -0
  105. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/src/openrewrite_migrate_python/migrate/module_cached_attribute.py +0 -0
  106. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/src/openrewrite_migrate_python/migrate/nntplib_migrations.py +0 -0
  107. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/src/openrewrite_migrate_python/migrate/os_deprecations.py +0 -0
  108. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/src/openrewrite_migrate_python/migrate/pathlib_deprecations.py +0 -0
  109. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/src/openrewrite_migrate_python/migrate/pep594_system_migrations.py +0 -0
  110. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/src/openrewrite_migrate_python/migrate/pipes_migrations.py +0 -0
  111. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/src/openrewrite_migrate_python/migrate/pkgutil_deprecations.py +0 -0
  112. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/src/openrewrite_migrate_python/migrate/platform_deprecations.py +0 -0
  113. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/src/openrewrite_migrate_python/migrate/pydantic_deprecations.py +0 -0
  114. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/src/openrewrite_migrate_python/migrate/pydantic_fields.py +0 -0
  115. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/src/openrewrite_migrate_python/migrate/pydantic_model_fields.py +0 -0
  116. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/src/openrewrite_migrate_python/migrate/re_deprecations.py +0 -0
  117. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/src/openrewrite_migrate_python/migrate/removed_modules_312.py +0 -0
  118. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/src/openrewrite_migrate_python/migrate/shutil_deprecations.py +0 -0
  119. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/src/openrewrite_migrate_python/migrate/socket_deprecations.py +0 -0
  120. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/src/openrewrite_migrate_python/migrate/ssl_deprecations.py +0 -0
  121. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/src/openrewrite_migrate_python/migrate/sys_deprecations.py +0 -0
  122. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/src/openrewrite_migrate_python/migrate/tarfile_deprecations.py +0 -0
  123. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/src/openrewrite_migrate_python/migrate/telnetlib_migrations.py +0 -0
  124. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/src/openrewrite_migrate_python/migrate/tempfile_deprecations.py +0 -0
  125. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/src/openrewrite_migrate_python/migrate/threading_deprecations.py +0 -0
  126. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/src/openrewrite_migrate_python/migrate/threading_is_alive_deprecation.py +0 -0
  127. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/src/openrewrite_migrate_python/migrate/typing_callable.py +0 -0
  128. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/src/openrewrite_migrate_python/migrate/typing_deprecations.py +0 -0
  129. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/src/openrewrite_migrate_python/migrate/typing_functional_syntax.py +0 -0
  130. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/src/openrewrite_migrate_python/migrate/typing_union_to_pipe.py +0 -0
  131. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/src/openrewrite_migrate_python/migrate/unittest_deprecations.py +0 -0
  132. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/src/openrewrite_migrate_python/migrate/upgrade_to_langchain02.py +0 -0
  133. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/src/openrewrite_migrate_python/migrate/upgrade_to_langchain1.py +0 -0
  134. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/src/openrewrite_migrate_python/migrate/upgrade_to_pandas.py +0 -0
  135. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/src/openrewrite_migrate_python/migrate/upgrade_to_pydantic.py +0 -0
  136. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/src/openrewrite_migrate_python/migrate/upgrade_to_python310.py +0 -0
  137. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/src/openrewrite_migrate_python/migrate/upgrade_to_python311.py +0 -0
  138. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/src/openrewrite_migrate_python/migrate/upgrade_to_python312.py +0 -0
  139. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/src/openrewrite_migrate_python/migrate/upgrade_to_python313.py +0 -0
  140. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/src/openrewrite_migrate_python/migrate/upgrade_to_python314.py +0 -0
  141. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/src/openrewrite_migrate_python/migrate/upgrade_to_python315.py +0 -0
  142. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/src/openrewrite_migrate_python/migrate/upgrade_to_python39.py +0 -0
  143. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/src/openrewrite_migrate_python/migrate/urllib_deprecations.py +0 -0
  144. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/src/openrewrite_migrate_python/migrate/uu_migrations.py +0 -0
  145. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/src/openrewrite_migrate_python/migrate/xdrlib_migrations.py +0 -0
  146. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/src/openrewrite_migrate_python/migrate/xml_deprecations.py +0 -0
  147. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/src/openrewrite_migrate_python.egg-info/dependency_links.txt +0 -0
  148. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/src/openrewrite_migrate_python.egg-info/entry_points.txt +0 -0
  149. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/src/openrewrite_migrate_python.egg-info/requires.txt +0 -0
  150. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/src/openrewrite_migrate_python.egg-info/top_level.txt +0 -0
  151. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/tests/test_aifc_migrations.py +0 -0
  152. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/tests/test_array_deprecations.py +0 -0
  153. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/tests/test_ast_deprecations.py +0 -0
  154. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/tests/test_asyncio_coroutine_to_async.py +0 -0
  155. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/tests/test_asyncio_deprecations.py +0 -0
  156. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/tests/test_avro_migrations.py +0 -0
  157. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/tests/test_backoff_to_tenacity.py +0 -0
  158. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/tests/test_calendar_deprecations.py +0 -0
  159. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/tests/test_cgi_parse_deprecations.py +0 -0
  160. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/tests/test_collections_abc_migrations.py +0 -0
  161. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/tests/test_configparser_deprecations.py +0 -0
  162. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/tests/test_datetime_utc.py +0 -0
  163. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/tests/test_distutils_deprecations.py +0 -0
  164. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/tests/test_distutils_migrations.py +0 -0
  165. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/tests/test_functools_deprecations.py +0 -0
  166. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/tests/test_future_imports.py +0 -0
  167. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/tests/test_gettext_deprecations.py +0 -0
  168. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/tests/test_glob_deprecations.py +0 -0
  169. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/tests/test_html_parser_deprecations.py +0 -0
  170. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/tests/test_imp_migrations.py +0 -0
  171. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/tests/test_importlib_resources_deprecations.py +0 -0
  172. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/tests/test_inspect_deprecations.py +0 -0
  173. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/tests/test_langchain_classic_imports.py +0 -0
  174. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/tests/test_langchain_community_imports.py +0 -0
  175. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/tests/test_langchain_provider_imports.py +0 -0
  176. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/tests/test_locale_deprecations.py +0 -0
  177. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/tests/test_locale_getdefaultlocale_deprecation.py +0 -0
  178. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/tests/test_macpath_deprecations.py +0 -0
  179. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/tests/test_mailcap_migrations.py +0 -0
  180. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/tests/test_markers.py +0 -0
  181. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/tests/test_module_cached_attribute.py +0 -0
  182. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/tests/test_os_deprecations.py +0 -0
  183. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/tests/test_pathlib_deprecations.py +0 -0
  184. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/tests/test_pep594_migrations.py +0 -0
  185. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/tests/test_pep594_system_migrations.py +0 -0
  186. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/tests/test_pkgutil_deprecations.py +0 -0
  187. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/tests/test_platform_deprecations.py +0 -0
  188. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/tests/test_pydantic_deprecations.py +0 -0
  189. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/tests/test_pydantic_fields.py +0 -0
  190. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/tests/test_pydantic_model_fields.py +0 -0
  191. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/tests/test_re_deprecations.py +0 -0
  192. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/tests/test_removed_modules_312.py +0 -0
  193. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/tests/test_shutil_deprecations.py +0 -0
  194. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/tests/test_socket_deprecations.py +0 -0
  195. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/tests/test_ssl_deprecations.py +0 -0
  196. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/tests/test_sys_deprecations.py +0 -0
  197. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/tests/test_tarfile_deprecations.py +0 -0
  198. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/tests/test_tempfile_deprecations.py +0 -0
  199. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/tests/test_threading_deprecations.py +0 -0
  200. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/tests/test_threading_extended.py +0 -0
  201. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/tests/test_threading_is_alive_deprecation.py +0 -0
  202. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/tests/test_typing_alias_moves.py +0 -0
  203. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/tests/test_typing_callable.py +0 -0
  204. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/tests/test_typing_deprecations.py +0 -0
  205. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/tests/test_typing_functional_syntax.py +0 -0
  206. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/tests/test_typing_union_to_pipe.py +0 -0
  207. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/tests/test_unittest_deprecations.py +0 -0
  208. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/tests/test_upgrade_recipes.py +0 -0
  209. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/tests/test_upgrade_to_pydantic.py +0 -0
  210. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/tests/test_urllib_deprecations.py +0 -0
  211. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/tests/test_xdrlib_migrations.py +0 -0
  212. {openrewrite_migrate_python-0.17.0.dev20261021175539 → openrewrite_migrate_python-0.17.0.dev20261022150922}/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.17.0.dev20261021175539
3
+ Version: 0.17.0.dev20261022150922
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.17.0.dev20261021175539" # Updated dynamically during release
8
+ version = "0.17.0.dev20261022150922" # 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,186 @@
1
+ """
2
+ Recipe for replacing the removed cgi.escape() with html.escape().
3
+
4
+ cgi.escape() was deprecated in Python 3.2 and removed in Python 3.8. Its
5
+ replacement html.escape() escapes quotes by default, where cgi.escape() did
6
+ not, so a call that relied on the default passes quote=False. A reference the
7
+ recipe cannot carry the default over for is marked instead.
8
+
9
+ See: https://docs.python.org/3/whatsnew/3.8.html#api-and-feature-removals
10
+ """
11
+
12
+ from typing import Any, List, Set
13
+
14
+ from rewrite import Cursor, ExecutionContext, Preconditions, Recipe, TreeVisitor
15
+ from rewrite.category import CategoryDescriptor
16
+ from rewrite.decorators import categorize
17
+ from rewrite.marketplace import Python
18
+ from rewrite.python.binding import maybe_rebind
19
+ from rewrite.python.binding_utils import import_bindings
20
+ from rewrite.python.method_matcher import MethodMatcher
21
+ from rewrite.python.preconditions import uses_method
22
+ from rewrite.python.template import template
23
+ from rewrite.python.tree import CompilationUnit, ExpressionStatement, NamedArgument, Star
24
+ from rewrite.python.visitor import PythonVisitor
25
+ from rewrite.java.support_types import JRightPadded, Space
26
+ from rewrite.java.tree import FieldAccess, Identifier, J, MethodInvocation
27
+
28
+ from ._markers import mark_deprecated
29
+
30
+ # Define category path: Python > Migrate > Python 3.8
31
+ _Python38 = [
32
+ *Python,
33
+ CategoryDescriptor(display_name="Migrate"),
34
+ CategoryDescriptor(display_name="Python 3.8"),
35
+ ]
36
+
37
+ _ESCAPE_PATTERN = "cgi escape(..)"
38
+ _ESCAPE = MethodMatcher.create(_ESCAPE_PATTERN)
39
+ _QUOTE_FALSE = template("escape(s, quote=False)")
40
+ _MANUAL = (
41
+ "`cgi.escape()` was removed in Python 3.8. Replace it with `html.escape()`, "
42
+ "passing `quote=False` unless quotes should now be escaped too"
43
+ )
44
+
45
+
46
+ @categorize(_Python38)
47
+ class ReplaceCgiEscape(Recipe):
48
+ """
49
+ Replace ``cgi.escape()`` with ``html.escape()``, keeping quotes unescaped.
50
+
51
+ ``cgi.escape(s)`` left quotes alone unless called with ``quote=True``, while
52
+ ``html.escape(s)`` escapes them by default. A call without a ``quote``
53
+ argument therefore gains ``quote=False``.
54
+
55
+ Example:
56
+ Before:
57
+ import cgi
58
+ safe = cgi.escape(text)
59
+ attr = cgi.escape(text, True)
60
+
61
+ After:
62
+ import html
63
+ safe = html.escape(text, quote=False)
64
+ attr = html.escape(text, True)
65
+ """
66
+
67
+ @property
68
+ def name(self) -> str:
69
+ return "org.openrewrite.python.migrate.ReplaceCgiEscape"
70
+
71
+ @property
72
+ def display_name(self) -> str:
73
+ return "Replace `cgi.escape()` with `html.escape()`"
74
+
75
+ @property
76
+ def description(self) -> str:
77
+ return (
78
+ "`cgi.escape()` was removed in Python 3.8. Replace it with `html.escape()`, "
79
+ "passing `quote=False` where the call gave no `quote` argument, since "
80
+ "`html.escape()` escapes quotes by default and `cgi.escape()` did not. An explicit "
81
+ "`quote` argument is kept as it is. A file that also refers to `cgi.escape` other than "
82
+ "by calling it, or calls it with unpacked `*args` or `**kwargs`, is left as it is, with "
83
+ "those references marked for a manual change. A file that never calls it is not visited."
84
+ )
85
+
86
+ @property
87
+ def tags(self) -> List[str]:
88
+ return ["python", "migration", "3.8", "cgi"]
89
+
90
+ def editor(self) -> TreeVisitor[Any, ExecutionContext]:
91
+ class Visitor(PythonVisitor[ExecutionContext]):
92
+ unsafe: Set[Any] = set()
93
+
94
+ def visit_compilation_unit(self, cu: CompilationUnit, p: ExecutionContext) -> J:
95
+ finder = _EscapeReferences()
96
+ finder.visit(cu, p)
97
+ self.unsafe = finder.unsafe
98
+ visited = super().visit_compilation_unit(cu, p)
99
+ if finder.found and not finder.unsafe:
100
+ maybe_rebind(self, "cgi", "html", from_member="escape")
101
+ return visited
102
+
103
+ def visit_method_invocation(self, method: MethodInvocation, p: ExecutionContext) -> J:
104
+ m = super().visit_method_invocation(method, p)
105
+ if not isinstance(m, MethodInvocation):
106
+ return m
107
+ if self.unsafe:
108
+ return mark_deprecated(m, _MANUAL) if m.id in self.unsafe else m
109
+ if not _ESCAPE.matches(m, cursor=self.cursor) or not _relies_on_default_quote(m):
110
+ return m
111
+ quote = _quote_false(self.cursor)
112
+ if quote is None:
113
+ return m
114
+ arguments = m.padding.arguments
115
+ last = arguments.padding.elements[-1]
116
+ elements = [
117
+ last.replace(_after=Space.EMPTY, _markers=quote.markers),
118
+ quote.replace(_after=last.after, _markers=last.markers),
119
+ ]
120
+ return m.padding.replace(_arguments=arguments.padding.replace(elements=elements))
121
+
122
+ def visit_field_access(self, field_access: FieldAccess, p: ExecutionContext) -> J:
123
+ fa = super().visit_field_access(field_access, p)
124
+ return mark_deprecated(fa, _MANUAL) if fa.id in self.unsafe else fa
125
+
126
+ def visit_identifier(self, ident: Identifier, p: ExecutionContext) -> J:
127
+ i = super().visit_identifier(ident, p)
128
+ return mark_deprecated(i, _MANUAL) if i.id in self.unsafe else i
129
+
130
+ return Preconditions.check(uses_method(_ESCAPE_PATTERN), Visitor())
131
+
132
+
133
+ class _EscapeReferences(PythonVisitor[ExecutionContext]):
134
+ """Finds the file's references to ``cgi.escape``, and those whose meaning the move would change."""
135
+
136
+ def __init__(self) -> None:
137
+ super().__init__()
138
+ self.found = False
139
+ self.unsafe: Set[Any] = set()
140
+
141
+ def visit_method_invocation(self, method: MethodInvocation, p: ExecutionContext) -> J:
142
+ if _ESCAPE.matches(method, cursor=self.cursor):
143
+ self.found = True
144
+ if not method.arguments or any(isinstance(arg, Star) for arg in method.arguments):
145
+ self.unsafe.add(method.id)
146
+ return super().visit_method_invocation(method, p)
147
+
148
+ def visit_field_access(self, field_access: FieldAccess, p: ExecutionContext) -> J:
149
+ # A call is a MethodInvocation, so `cgi.escape` as a FieldAccess is passed around, not called.
150
+ target = field_access.target
151
+ if field_access.name.simple_name == "escape" and isinstance(target, Identifier):
152
+ binding = import_bindings(self).reference(Cursor(self.cursor, target), target)
153
+ if binding is not None and binding.module == "cgi" and binding.member is None:
154
+ self.found = True
155
+ self.unsafe.add(field_access.id)
156
+ return super().visit_field_access(field_access, p)
157
+
158
+ def visit_identifier(self, ident: Identifier, p: ExecutionContext) -> J:
159
+ binding = import_bindings(self).reference(self.cursor, ident)
160
+ if binding is not None and binding.module == "cgi" and binding.member == "escape":
161
+ parent = self.cursor.parent_tree_cursor().value
162
+ if not (isinstance(parent, MethodInvocation) and parent.name is ident):
163
+ self.found = True
164
+ self.unsafe.add(ident.id)
165
+ return super().visit_identifier(ident, p)
166
+
167
+
168
+ def _relies_on_default_quote(call: MethodInvocation) -> bool:
169
+ """Whether ``call`` passes only the string, by position or as ``s=``."""
170
+ if len(call.arguments) != 1:
171
+ return False
172
+ only = call.arguments[0]
173
+ if isinstance(only, NamedArgument):
174
+ return only.name.simple_name == "s"
175
+ return not isinstance(only, Star)
176
+
177
+
178
+ def _quote_false(cursor: Cursor) -> JRightPadded | None:
179
+ """A ``quote=False`` argument as a parse gives it, padded to follow a comma."""
180
+ call = _QUOTE_FALSE.apply(cursor, format=False)
181
+ if isinstance(call, ExpressionStatement):
182
+ call = call.expression
183
+ if not isinstance(call, MethodInvocation):
184
+ return None
185
+ quote = call.padding.arguments.padding.elements[-1]
186
+ return quote.replace(_element=quote.element.replace(prefix=Space.SINGLE_SPACE))
@@ -6,7 +6,7 @@ The following functions were deprecated in Python 3.2 and removed in Python 3.8:
6
6
  - cgi.parse_qs() -> urllib.parse.parse_qs()
7
7
  - cgi.parse_qsl() -> urllib.parse.parse_qsl()
8
8
 
9
- Note: cgi.escape() -> html.escape() is handled in cgi_migrations.py.
9
+ Note: cgi.escape() -> html.escape() is handled in cgi_escape_deprecations.py.
10
10
 
11
11
  See: https://docs.python.org/3/whatsnew/3.8.html#api-and-feature-removals
12
12
  """
@@ -35,6 +35,7 @@ from rewrite.utils import random_id
35
35
 
36
36
  from openrewrite_code_quality_python.cleanup._literals import is_string_literal
37
37
  from openrewrite_code_quality_python.codequality._side_effects import is_side_effect_free
38
+ from openrewrite_code_quality_python.codequality._trivia import has_comments
38
39
 
39
40
  from ._slots import as_slot_of
40
41
 
@@ -173,6 +174,10 @@ def _convert_format_to_fstring(method: MethodInvocation) -> FormattedString | No
173
174
  if not isinstance(select, Literal):
174
175
  return None
175
176
 
177
+ # The f-string is rebuilt from the parts, which drops every comment inside the call
178
+ if has_comments(method.replace(prefix=Space.EMPTY)):
179
+ return None
180
+
176
181
  value_source = select.value_source
177
182
  if not value_source:
178
183
  return None
@@ -366,7 +371,7 @@ class ReplaceStrFormatWithFString(Recipe):
366
371
  "conversion is safe. A format string with a backslash escape, a raw or bytes prefix, "
367
372
  "or a field reading an attribute or index is left alone. So is a call with an unpacked "
368
373
  "argument, a string literal argument, or an argument that has side effects and is "
369
- "used more than once."
374
+ "used more than once, and a call with a comment inside it, which the f-string would drop."
370
375
  )
371
376
 
372
377
  @property
@@ -449,6 +454,10 @@ def _convert_percent_to_fstring(binary: Binary) -> FormattedString | None:
449
454
  if not isinstance(left, Literal):
450
455
  return None
451
456
 
457
+ # The f-string is rebuilt from the parts, which drops every comment inside the expression
458
+ if has_comments(binary.replace(prefix=Space.EMPTY)):
459
+ return None
460
+
452
461
  value_source = left.value_source
453
462
  if not value_source:
454
463
  return None
@@ -581,7 +590,8 @@ class ReplacePercentFormatWithFString(Recipe):
581
590
  "Only converts `%s` and `%r` specifiers where the format string is "
582
591
  "a literal and the conversion is safe. A single operand that is not a "
583
592
  "tuple literal must have a type that resolves to a non-tuple, such as "
584
- "`str` or `int`, since a tuple would be spread over the specifiers."
593
+ "`str` or `int`, since a tuple would be spread over the specifiers. "
594
+ "An expression with a comment inside it is left alone, since the f-string would drop it."
585
595
  )
586
596
 
587
597
  @property
@@ -0,0 +1,227 @@
1
+ """
2
+ Recipe for replacing deprecated sys.last_type/last_value/last_traceback
3
+ with sys.last_exc equivalents.
4
+
5
+ sys.last_type, sys.last_value, and sys.last_traceback were deprecated in
6
+ Python 3.12 in favor of sys.last_exc:
7
+
8
+ - sys.last_value -> sys.last_exc
9
+ - sys.last_type -> type(sys.last_exc)
10
+ - sys.last_traceback -> sys.last_exc.__traceback__
11
+
12
+ See: https://docs.python.org/3/whatsnew/3.12.html#deprecated
13
+ """
14
+
15
+ from typing import Any, List
16
+
17
+ from rewrite import Cursor, ExecutionContext, Preconditions, Recipe, TreeVisitor
18
+ from rewrite.category import CategoryDescriptor
19
+ from rewrite.decorators import categorize
20
+ from rewrite.marketplace import Python
21
+ from rewrite.python.binding_utils import import_bindings
22
+ from rewrite.python.method_matcher import MethodMatcher
23
+ from rewrite.python.preconditions import uses_import
24
+ from rewrite.python.remove_import import RemoveImportOptions, maybe_remove_import
25
+ from rewrite.python.scope_utils import scope_of
26
+ from rewrite.python.template import template
27
+ from rewrite.python.visitor import PythonVisitor
28
+ from rewrite.python.tree import (
29
+ ChainedAssignment,
30
+ CollectionLiteral,
31
+ CompilationUnit,
32
+ ComprehensionExpression,
33
+ Del,
34
+ ExpressionStatement,
35
+ Star,
36
+ TypeHintedExpression,
37
+ )
38
+ from rewrite.java.tree import (
39
+ Assignment,
40
+ AssignmentOperation,
41
+ FieldAccess,
42
+ ForEachLoop,
43
+ Identifier,
44
+ J,
45
+ Literal,
46
+ MethodInvocation,
47
+ Parentheses,
48
+ )
49
+
50
+ # Define category path: Python > Migrate > Python 3.12
51
+ _Python312 = [
52
+ *Python,
53
+ CategoryDescriptor(display_name="Migrate"),
54
+ CategoryDescriptor(display_name="Python 3.12"),
55
+ ]
56
+
57
+ _REPLACEMENTS = {
58
+ attribute: template(replacement, context=["import sys"])
59
+ for attribute, replacement in (
60
+ ("last_value", "sys.last_exc"),
61
+ ("last_type", "type(sys.last_exc)"),
62
+ ("last_traceback", "sys.last_exc.__traceback__"),
63
+ )
64
+ }
65
+
66
+ _HASATTR = MethodMatcher.create("builtins hasattr(..)")
67
+
68
+
69
+ @categorize(_Python312)
70
+ class ReplaceSysLastExcInfo(Recipe):
71
+ """
72
+ Replace ``sys.last_type``, ``sys.last_value``, and ``sys.last_traceback`` with
73
+ their ``sys.last_exc``-based equivalents.
74
+
75
+ These attributes were deprecated in Python 3.12 in favor of ``sys.last_exc``
76
+ which provides the exception object directly.
77
+
78
+ Example:
79
+ Before:
80
+ import sys
81
+ if hasattr(sys, "last_type"):
82
+ exc_type = sys.last_type
83
+ exc_value = sys.last_value
84
+ exc_tb = sys.last_traceback
85
+
86
+ After:
87
+ import sys
88
+ if hasattr(sys, "last_exc"):
89
+ exc_type = type(sys.last_exc)
90
+ exc_value = sys.last_exc
91
+ exc_tb = sys.last_exc.__traceback__
92
+ """
93
+
94
+ @property
95
+ def name(self) -> str:
96
+ return "org.openrewrite.python.migrate.ReplaceSysLastExcInfo"
97
+
98
+ @property
99
+ def display_name(self) -> str:
100
+ return "Replace `sys.last_type` / `sys.last_value` / `sys.last_traceback` with `sys.last_exc`"
101
+
102
+ @property
103
+ def description(self) -> str:
104
+ return (
105
+ "`sys.last_type`, `sys.last_value`, and `sys.last_traceback` were "
106
+ "deprecated in Python 3.12. "
107
+ "Replace reads of them with their `sys.last_exc`-based equivalents: "
108
+ "`type(sys.last_exc)`, `sys.last_exc`, and `sys.last_exc.__traceback__` "
109
+ "respectively, and a `hasattr(sys, \"last_type\")` guard with "
110
+ "`hasattr(sys, \"last_exc\")`. Assignment, `del`, `for` and `with` targets "
111
+ "are left alone, and so is every read in a file that assigns or deletes "
112
+ "one of the attributes, since `sys.last_exc` would not hold what it set. "
113
+ "`sys.last_type` is left alone where `type` is shadowed."
114
+ )
115
+
116
+ @property
117
+ def tags(self) -> List[str]:
118
+ return ["python", "migration", "3.12", "sys"]
119
+
120
+ def editor(self) -> TreeVisitor[Any, ExecutionContext]:
121
+ class Visitor(PythonVisitor[ExecutionContext]):
122
+ def visit_compilation_unit(self, cu: CompilationUnit, p: ExecutionContext) -> J:
123
+ finder = _WriteFinder()
124
+ finder.visit(cu, p)
125
+ if finder.found:
126
+ return cu
127
+ return super().visit_compilation_unit(cu, p)
128
+
129
+ def visit_field_access(self, field_access: FieldAccess, p: ExecutionContext) -> J:
130
+ fa = super().visit_field_access(field_access, p)
131
+ if not isinstance(fa, FieldAccess):
132
+ return fa
133
+ member = _sys_attribute(self, fa)
134
+ return fa if member is None else self._replace(fa, member)
135
+
136
+ def visit_identifier(self, ident: Identifier, p: ExecutionContext) -> J:
137
+ i = super().visit_identifier(ident, p)
138
+ if not isinstance(i, Identifier):
139
+ return i
140
+ binding = import_bindings(self).reference(self.cursor, i)
141
+ if binding is None or binding.module != "sys" or binding.member not in _REPLACEMENTS:
142
+ return i
143
+ if _is_written(self.cursor):
144
+ return i
145
+ replaced = self._replace(i, binding.member)
146
+ if replaced is not i:
147
+ maybe_remove_import(self, RemoveImportOptions(module="sys", name=binding.member))
148
+ return replaced
149
+
150
+ def visit_method_invocation(self, method: MethodInvocation, p: ExecutionContext) -> J:
151
+ m = super().visit_method_invocation(method, p)
152
+ if not isinstance(m, MethodInvocation) or not _HASATTR.matches(m, cursor=self.cursor):
153
+ return m
154
+ if len(m.arguments) != 2:
155
+ return m
156
+ receiver, attribute = m.arguments
157
+ if not isinstance(receiver, Identifier) or not isinstance(attribute, Literal):
158
+ return m
159
+ binding = import_bindings(self).reference(Cursor(self.cursor, receiver), receiver)
160
+ if binding is None or binding.module != "sys" or binding.member is not None:
161
+ return m
162
+ if attribute.value not in _REPLACEMENTS or attribute.value_source is None:
163
+ return m
164
+ guard = attribute.replace(
165
+ value="last_exc",
166
+ value_source=attribute.value_source.replace(str(attribute.value), "last_exc"),
167
+ )
168
+ arguments = m.padding.arguments
169
+ padded = arguments.padding.elements
170
+ padded = [padded[0], padded[1].replace(_element=guard)]
171
+ return m.padding.replace(_arguments=arguments.padding.replace(elements=padded))
172
+
173
+ def _replace(self, tree: J, member: str) -> J:
174
+ if member == "last_type" and scope_of(self.cursor).declares("type"):
175
+ return tree
176
+ try:
177
+ return _REPLACEMENTS[member].apply(self.cursor, visitor=self) or tree
178
+ except ValueError:
179
+ # The template refuses a file where `sys` is bound to something else.
180
+ return tree
181
+
182
+ return Preconditions.check(uses_import("sys"), Visitor())
183
+
184
+
185
+ class _WriteFinder(PythonVisitor[ExecutionContext]):
186
+ """Finds an assignment to or ``del`` of one of the deprecated ``sys`` attributes."""
187
+
188
+ found = False
189
+
190
+ def visit_field_access(self, field_access: FieldAccess, p: ExecutionContext) -> J:
191
+ if not self.found and _sys_attribute(self, field_access) is not None and _is_written(self.cursor):
192
+ self.found = True
193
+ return super().visit_field_access(field_access, p)
194
+
195
+
196
+ def _sys_attribute(visitor: PythonVisitor, field_access: FieldAccess) -> str | None:
197
+ """The deprecated attribute ``field_access`` names on the ``sys`` module, if it does."""
198
+ if not isinstance(field_access.target, Identifier) or field_access.name.simple_name not in _REPLACEMENTS:
199
+ return None
200
+ binding = import_bindings(visitor).reference(visitor.cursor, field_access.target)
201
+ if binding is None or binding.module != "sys" or binding.member is not None:
202
+ return None
203
+ return field_access.name.simple_name
204
+
205
+
206
+ def _is_written(cursor: Cursor) -> bool:
207
+ """Whether the expression at ``cursor`` is assigned or deleted rather than read."""
208
+ node = cursor.value
209
+ parent = cursor.parent_tree_cursor()
210
+ while True:
211
+ holder = parent.value
212
+ if isinstance(holder, TypeHintedExpression):
213
+ return holder.expression is node
214
+ if not isinstance(holder, (Parentheses, Star, CollectionLiteral, ExpressionStatement)):
215
+ break
216
+ node = holder
217
+ parent = parent.parent_tree_cursor()
218
+ target = parent.value
219
+ if isinstance(target, (Assignment, AssignmentOperation)):
220
+ return target.variable is node
221
+ if isinstance(target, ChainedAssignment):
222
+ return any(variable is node for variable in target.variables)
223
+ if isinstance(target, ForEachLoop.Control):
224
+ return target.variable is node
225
+ if isinstance(target, ComprehensionExpression.Clause):
226
+ return target.iterator_variable is node
227
+ return isinstance(target, Del)
@@ -22,8 +22,8 @@ class UpgradeToPython38(Recipe):
22
22
 
23
23
  Key changes:
24
24
  - Replace ``time.clock()`` with ``time.perf_counter()``
25
- - Replace ``cgi.escape()`` with ``html.escape()``, which also escapes quotes unless
26
- called with ``quote=False``
25
+ - Replace ``cgi.escape()`` with ``html.escape()``, passing ``quote=False`` where the
26
+ call relied on ``cgi.escape()`` leaving quotes alone
27
27
  - Replace ``cgi.parse_qs()`` / ``cgi.parse_qsl()`` with ``urllib.parse`` equivalents
28
28
  - Replace ``platform.popen()`` with ``subprocess.check_output()``
29
29
  - Replace ``tarfile.filemode`` with ``stat.filemode``
@@ -48,8 +48,8 @@ class UpgradeToPython38(Recipe):
48
48
  def description(self) -> str:
49
49
  return (
50
50
  "Migrate deprecated APIs and detect legacy patterns for Python 3.8 compatibility. "
51
- "`cgi.escape()` becomes `html.escape()`, which also escapes quotes unless called "
52
- "with `quote=False`."
51
+ "`cgi.escape()` becomes `html.escape()`, with `quote=False` where the call relied "
52
+ "on `cgi.escape()` leaving quotes alone."
53
53
  )
54
54
 
55
55
  @property
@@ -58,6 +58,7 @@ class UpgradeToPython38(Recipe):
58
58
 
59
59
  def recipe_list(self) -> List[Recipe]:
60
60
  """Return the list of recipes to apply for Python 3.8 upgrade."""
61
+ from .cgi_escape_deprecations import ReplaceCgiEscape
61
62
  from .cgi_parse_deprecations import ReplaceCgiParseQs, ReplaceCgiParseQsl
62
63
  from .functools_deprecations import FindFunctoolsCmpToKey
63
64
  from .future_imports import RemoveFutureImports
@@ -69,8 +70,8 @@ class UpgradeToPython38(Recipe):
69
70
  return [
70
71
  # Auto-fix: time.clock() -> time.perf_counter()
71
72
  ChangeImport(old_module="time", old_name="clock", new_module="time", new_name="perf_counter"),
72
- # Auto-fix: cgi.escape() -> html.escape(), which also escapes quotes by default
73
- ChangeImport(old_module="cgi", old_name="escape", new_module="html"),
73
+ # Auto-fix: cgi.escape() -> html.escape(..., quote=False)
74
+ ReplaceCgiEscape(),
74
75
  # Auto-fix: cgi.parse_qs() / cgi.parse_qsl() -> urllib.parse
75
76
  ReplaceCgiParseQs(),
76
77
  ReplaceCgiParseQsl(),
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: openrewrite-migrate-python
3
- Version: 0.17.0.dev20261021175539
3
+ Version: 0.17.0.dev20261022150922
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
@@ -72,6 +72,7 @@ src/openrewrite_migrate_python/migrate/asyncio_deprecations.py
72
72
  src/openrewrite_migrate_python/migrate/avro_migrations.py
73
73
  src/openrewrite_migrate_python/migrate/backoff_to_tenacity.py
74
74
  src/openrewrite_migrate_python/migrate/calendar_deprecations.py
75
+ src/openrewrite_migrate_python/migrate/cgi_escape_deprecations.py
75
76
  src/openrewrite_migrate_python/migrate/cgi_migrations.py
76
77
  src/openrewrite_migrate_python/migrate/cgi_parse_deprecations.py
77
78
  src/openrewrite_migrate_python/migrate/collections_abc_migrations.py
@@ -147,6 +148,7 @@ tests/test_asyncio_deprecations.py
147
148
  tests/test_avro_migrations.py
148
149
  tests/test_backoff_to_tenacity.py
149
150
  tests/test_calendar_deprecations.py
151
+ tests/test_cgi_escape_deprecations.py
150
152
  tests/test_cgi_parse_deprecations.py
151
153
  tests/test_change_import_recipes.py
152
154
  tests/test_collections_abc_migrations.py