openrewrite-migrate-python 0.20.0__tar.gz → 0.22.0__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 (236) hide show
  1. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/PKG-INFO +1 -1
  2. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/pyproject.toml +1 -1
  3. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/src/openrewrite_migrate_python/migrate/__init__.py +4 -1
  4. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/src/openrewrite_migrate_python/migrate/datetime_utc.py +25 -23
  5. openrewrite_migrate_python-0.22.0/src/openrewrite_migrate_python/migrate/mock_assertions.py +117 -0
  6. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/src/openrewrite_migrate_python/migrate/pipes_migrations.py +41 -0
  7. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/src/openrewrite_migrate_python/migrate/upgrade_to_python312.py +3 -0
  8. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/src/openrewrite_migrate_python/migrate/upgrade_to_python313.py +3 -1
  9. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/src/openrewrite_migrate_python.egg-info/PKG-INFO +1 -1
  10. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/src/openrewrite_migrate_python.egg-info/SOURCES.txt +3 -0
  11. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/tests/test_datetime_utc.py +14 -14
  12. openrewrite_migrate_python-0.22.0/tests/test_mock_assertions.py +86 -0
  13. openrewrite_migrate_python-0.22.0/tests/test_pipes_migrations.py +67 -0
  14. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/tests/test_upgrade_recipes.py +4 -4
  15. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/setup.cfg +0 -0
  16. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/src/openrewrite_code_quality_python/__init__.py +0 -0
  17. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/src/openrewrite_code_quality_python/cleanup/__init__.py +0 -0
  18. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/src/openrewrite_code_quality_python/cleanup/_literals.py +0 -0
  19. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/src/openrewrite_code_quality_python/cleanup/_negation.py +0 -0
  20. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/src/openrewrite_code_quality_python/cleanup/assign_return.py +0 -0
  21. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/src/openrewrite_code_quality_python/cleanup/attr_access.py +0 -0
  22. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/src/openrewrite_code_quality_python/cleanup/boolean_simplification.py +0 -0
  23. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/src/openrewrite_code_quality_python/cleanup/collection_literals.py +0 -0
  24. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/src/openrewrite_code_quality_python/cleanup/comparison_simplification.py +0 -0
  25. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/src/openrewrite_code_quality_python/cleanup/complex_transforms.py +0 -0
  26. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/src/openrewrite_code_quality_python/cleanup/comprehension_cleanup.py +0 -0
  27. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/src/openrewrite_code_quality_python/cleanup/conditionals.py +0 -0
  28. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/src/openrewrite_code_quality_python/cleanup/datetime_cleanup.py +0 -0
  29. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/src/openrewrite_code_quality_python/cleanup/dict_cleanup.py +0 -0
  30. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/src/openrewrite_code_quality_python/cleanup/exception_cleanup.py +0 -0
  31. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/src/openrewrite_code_quality_python/cleanup/expression_simplification.py +0 -0
  32. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/src/openrewrite_code_quality_python/cleanup/logger_warn.py +0 -0
  33. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/src/openrewrite_code_quality_python/cleanup/loop_cleanup.py +0 -0
  34. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/src/openrewrite_code_quality_python/cleanup/merge_nested_with.py +0 -0
  35. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/src/openrewrite_code_quality_python/cleanup/merge_startswith_endswith.py +0 -0
  36. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/src/openrewrite_code_quality_python/cleanup/naming_conventions.py +0 -0
  37. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/src/openrewrite_code_quality_python/cleanup/negated_operators.py +0 -0
  38. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/src/openrewrite_code_quality_python/cleanup/none_and_identity.py +0 -0
  39. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/src/openrewrite_code_quality_python/cleanup/object_inheritance.py +0 -0
  40. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/src/openrewrite_code_quality_python/cleanup/pandas_cleanup.py +0 -0
  41. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/src/openrewrite_code_quality_python/cleanup/python_best_practices.py +0 -0
  42. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/src/openrewrite_code_quality_python/cleanup/range_cleanup.py +0 -0
  43. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/src/openrewrite_code_quality_python/cleanup/redundant_code.py +0 -0
  44. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/src/openrewrite_code_quality_python/cleanup/remove_trailing_return_none.py +0 -0
  45. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/src/openrewrite_code_quality_python/cleanup/string_cleanup.py +0 -0
  46. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/src/openrewrite_code_quality_python/cleanup/unreachable_code.py +0 -0
  47. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/src/openrewrite_code_quality_python/cleanup/use_items.py +0 -0
  48. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/src/openrewrite_code_quality_python/cleanup/use_list_clear.py +0 -0
  49. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/src/openrewrite_code_quality_python/cleanup/yoda_conditions.py +0 -0
  50. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/src/openrewrite_code_quality_python/codequality/__init__.py +0 -0
  51. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/src/openrewrite_code_quality_python/codequality/_grouping.py +0 -0
  52. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/src/openrewrite_code_quality_python/codequality/_reindent.py +0 -0
  53. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/src/openrewrite_code_quality_python/codequality/_semantically_equal.py +0 -0
  54. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/src/openrewrite_code_quality_python/codequality/_side_effects.py +0 -0
  55. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/src/openrewrite_code_quality_python/codequality/_trivia.py +0 -0
  56. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/src/openrewrite_code_quality_python/codequality/_truth_value.py +0 -0
  57. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/src/openrewrite_code_quality_python/codequality/all_branches_identical.py +0 -0
  58. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/src/openrewrite_code_quality_python/codequality/boolean_checks_not_inverted.py +0 -0
  59. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/src/openrewrite_code_quality_python/codequality/code_quality.py +0 -0
  60. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/src/openrewrite_code_quality_python/codequality/collapsible_if_statements.py +0 -0
  61. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/src/openrewrite_code_quality_python/codequality/find_suspicious_chained_comparison.py +0 -0
  62. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/src/openrewrite_code_quality_python/codequality/merge_identical_branches.py +0 -0
  63. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/src/openrewrite_code_quality_python/codequality/remove_duplicate_conditions.py +0 -0
  64. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/src/openrewrite_code_quality_python/codequality/remove_self_assignment.py +0 -0
  65. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/src/openrewrite_code_quality_python/codequality/remove_unconditional_value_overwrite.py +0 -0
  66. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/src/openrewrite_code_quality_python/codequality/simplify_boolean_literal.py +0 -0
  67. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/src/openrewrite_code_quality_python/codequality/simplify_redundant_logical_expression.py +0 -0
  68. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/src/openrewrite_migrate_python/__init__.py +0 -0
  69. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/src/openrewrite_migrate_python/migrate/_decorators.py +0 -0
  70. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/src/openrewrite_migrate_python/migrate/_finders.py +0 -0
  71. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/src/openrewrite_migrate_python/migrate/_langchain_tables.py +0 -0
  72. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/src/openrewrite_migrate_python/migrate/_markers.py +0 -0
  73. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/src/openrewrite_migrate_python/migrate/_method_renames.py +0 -0
  74. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/src/openrewrite_migrate_python/migrate/_module_imports.py +0 -0
  75. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/src/openrewrite_migrate_python/migrate/_slots.py +0 -0
  76. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/src/openrewrite_migrate_python/migrate/aifc_migrations.py +0 -0
  77. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/src/openrewrite_migrate_python/migrate/array_deprecations.py +0 -0
  78. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/src/openrewrite_migrate_python/migrate/ast_deprecations.py +0 -0
  79. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/src/openrewrite_migrate_python/migrate/asyncio_coroutine_to_async.py +0 -0
  80. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/src/openrewrite_migrate_python/migrate/asyncio_deprecations.py +0 -0
  81. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/src/openrewrite_migrate_python/migrate/avro_migrations.py +0 -0
  82. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/src/openrewrite_migrate_python/migrate/backoff_to_tenacity.py +0 -0
  83. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/src/openrewrite_migrate_python/migrate/builtins_deprecations.py +0 -0
  84. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/src/openrewrite_migrate_python/migrate/calendar_deprecations.py +0 -0
  85. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/src/openrewrite_migrate_python/migrate/cgi_escape_deprecations.py +0 -0
  86. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/src/openrewrite_migrate_python/migrate/cgi_migrations.py +0 -0
  87. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/src/openrewrite_migrate_python/migrate/cgi_parse_deprecations.py +0 -0
  88. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/src/openrewrite_migrate_python/migrate/collections_abc_migrations.py +0 -0
  89. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/src/openrewrite_migrate_python/migrate/configparser_deprecations.py +0 -0
  90. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/src/openrewrite_migrate_python/migrate/ctypes_deprecations.py +0 -0
  91. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/src/openrewrite_migrate_python/migrate/distutils_deprecations.py +0 -0
  92. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/src/openrewrite_migrate_python/migrate/distutils_migrations.py +0 -0
  93. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/src/openrewrite_migrate_python/migrate/functools_deprecations.py +0 -0
  94. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/src/openrewrite_migrate_python/migrate/future_imports.py +0 -0
  95. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/src/openrewrite_migrate_python/migrate/gettext_deprecations.py +0 -0
  96. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/src/openrewrite_migrate_python/migrate/glob_deprecations.py +0 -0
  97. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/src/openrewrite_migrate_python/migrate/html_parser_deprecations.py +0 -0
  98. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/src/openrewrite_migrate_python/migrate/http_server_deprecations.py +0 -0
  99. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/src/openrewrite_migrate_python/migrate/imp_migrations.py +0 -0
  100. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/src/openrewrite_migrate_python/migrate/importlib_deprecations.py +0 -0
  101. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/src/openrewrite_migrate_python/migrate/importlib_resources_deprecations.py +0 -0
  102. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/src/openrewrite_migrate_python/migrate/inspect_deprecations.py +0 -0
  103. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/src/openrewrite_migrate_python/migrate/langchain_classic_imports.py +0 -0
  104. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/src/openrewrite_migrate_python/migrate/langchain_community_imports.py +0 -0
  105. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/src/openrewrite_migrate_python/migrate/langchain_provider_imports.py +0 -0
  106. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/src/openrewrite_migrate_python/migrate/locale_deprecations.py +0 -0
  107. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/src/openrewrite_migrate_python/migrate/locale_getdefaultlocale_deprecation.py +0 -0
  108. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/src/openrewrite_migrate_python/migrate/macpath_deprecations.py +0 -0
  109. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/src/openrewrite_migrate_python/migrate/mailcap_migrations.py +0 -0
  110. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/src/openrewrite_migrate_python/migrate/module_cached_attribute.py +0 -0
  111. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/src/openrewrite_migrate_python/migrate/nntplib_migrations.py +0 -0
  112. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/src/openrewrite_migrate_python/migrate/os_deprecations.py +0 -0
  113. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/src/openrewrite_migrate_python/migrate/pathlib_deprecations.py +0 -0
  114. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/src/openrewrite_migrate_python/migrate/pep594_system_migrations.py +0 -0
  115. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/src/openrewrite_migrate_python/migrate/pkgutil_deprecations.py +0 -0
  116. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/src/openrewrite_migrate_python/migrate/platform_deprecations.py +0 -0
  117. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/src/openrewrite_migrate_python/migrate/profile_deprecations.py +0 -0
  118. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/src/openrewrite_migrate_python/migrate/pydantic_deprecations.py +0 -0
  119. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/src/openrewrite_migrate_python/migrate/pydantic_fields.py +0 -0
  120. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/src/openrewrite_migrate_python/migrate/pydantic_model_fields.py +0 -0
  121. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/src/openrewrite_migrate_python/migrate/re_deprecations.py +0 -0
  122. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/src/openrewrite_migrate_python/migrate/removed_modules_312.py +0 -0
  123. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/src/openrewrite_migrate_python/migrate/shutil_deprecations.py +0 -0
  124. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/src/openrewrite_migrate_python/migrate/socket_deprecations.py +0 -0
  125. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/src/openrewrite_migrate_python/migrate/sre_migrations.py +0 -0
  126. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/src/openrewrite_migrate_python/migrate/ssl_deprecations.py +0 -0
  127. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/src/openrewrite_migrate_python/migrate/string_formatting.py +0 -0
  128. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/src/openrewrite_migrate_python/migrate/sys_deprecations.py +0 -0
  129. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/src/openrewrite_migrate_python/migrate/sys_last_deprecations.py +0 -0
  130. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/src/openrewrite_migrate_python/migrate/tarfile_deprecations.py +0 -0
  131. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/src/openrewrite_migrate_python/migrate/telnetlib_migrations.py +0 -0
  132. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/src/openrewrite_migrate_python/migrate/tempfile_deprecations.py +0 -0
  133. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/src/openrewrite_migrate_python/migrate/text_encoding.py +0 -0
  134. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/src/openrewrite_migrate_python/migrate/threading_deprecations.py +0 -0
  135. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/src/openrewrite_migrate_python/migrate/threading_is_alive_deprecation.py +0 -0
  136. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/src/openrewrite_migrate_python/migrate/types_deprecations.py +0 -0
  137. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/src/openrewrite_migrate_python/migrate/typing_callable.py +0 -0
  138. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/src/openrewrite_migrate_python/migrate/typing_deprecations.py +0 -0
  139. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/src/openrewrite_migrate_python/migrate/typing_functional_syntax.py +0 -0
  140. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/src/openrewrite_migrate_python/migrate/typing_union_to_pipe.py +0 -0
  141. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/src/openrewrite_migrate_python/migrate/unittest_deprecations.py +0 -0
  142. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/src/openrewrite_migrate_python/migrate/upgrade_to_langchain02.py +0 -0
  143. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/src/openrewrite_migrate_python/migrate/upgrade_to_langchain1.py +0 -0
  144. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/src/openrewrite_migrate_python/migrate/upgrade_to_pandas.py +0 -0
  145. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/src/openrewrite_migrate_python/migrate/upgrade_to_pydantic.py +0 -0
  146. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/src/openrewrite_migrate_python/migrate/upgrade_to_python310.py +0 -0
  147. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/src/openrewrite_migrate_python/migrate/upgrade_to_python311.py +0 -0
  148. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/src/openrewrite_migrate_python/migrate/upgrade_to_python314.py +0 -0
  149. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/src/openrewrite_migrate_python/migrate/upgrade_to_python315.py +0 -0
  150. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/src/openrewrite_migrate_python/migrate/upgrade_to_python38.py +0 -0
  151. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/src/openrewrite_migrate_python/migrate/upgrade_to_python39.py +0 -0
  152. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/src/openrewrite_migrate_python/migrate/urllib_deprecations.py +0 -0
  153. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/src/openrewrite_migrate_python/migrate/uu_migrations.py +0 -0
  154. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/src/openrewrite_migrate_python/migrate/wave_deprecations.py +0 -0
  155. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/src/openrewrite_migrate_python/migrate/webbrowser_deprecations.py +0 -0
  156. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/src/openrewrite_migrate_python/migrate/xdrlib_migrations.py +0 -0
  157. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/src/openrewrite_migrate_python/migrate/xml_deprecations.py +0 -0
  158. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/src/openrewrite_migrate_python.egg-info/dependency_links.txt +0 -0
  159. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/src/openrewrite_migrate_python.egg-info/entry_points.txt +0 -0
  160. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/src/openrewrite_migrate_python.egg-info/requires.txt +0 -0
  161. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/src/openrewrite_migrate_python.egg-info/top_level.txt +0 -0
  162. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/tests/test_aifc_migrations.py +0 -0
  163. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/tests/test_array_deprecations.py +0 -0
  164. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/tests/test_ast_deprecations.py +0 -0
  165. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/tests/test_asyncio_coroutine_to_async.py +0 -0
  166. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/tests/test_asyncio_deprecations.py +0 -0
  167. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/tests/test_avro_migrations.py +0 -0
  168. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/tests/test_backoff_to_tenacity.py +0 -0
  169. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/tests/test_builtins_deprecations.py +0 -0
  170. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/tests/test_calendar_deprecations.py +0 -0
  171. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/tests/test_cgi_escape_deprecations.py +0 -0
  172. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/tests/test_cgi_parse_deprecations.py +0 -0
  173. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/tests/test_change_import_recipes.py +0 -0
  174. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/tests/test_collections_abc_migrations.py +0 -0
  175. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/tests/test_configparser_deprecations.py +0 -0
  176. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/tests/test_ctypes_deprecations.py +0 -0
  177. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/tests/test_distutils_deprecations.py +0 -0
  178. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/tests/test_distutils_migrations.py +0 -0
  179. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/tests/test_functools_deprecations.py +0 -0
  180. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/tests/test_future_imports.py +0 -0
  181. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/tests/test_gettext_deprecations.py +0 -0
  182. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/tests/test_glob_deprecations.py +0 -0
  183. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/tests/test_html_parser_deprecations.py +0 -0
  184. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/tests/test_http_server_deprecations.py +0 -0
  185. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/tests/test_imp_migrations.py +0 -0
  186. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/tests/test_importlib_deprecations.py +0 -0
  187. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/tests/test_importlib_resources_deprecations.py +0 -0
  188. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/tests/test_inspect_deprecations.py +0 -0
  189. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/tests/test_langchain_classic_imports.py +0 -0
  190. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/tests/test_langchain_community_imports.py +0 -0
  191. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/tests/test_langchain_provider_imports.py +0 -0
  192. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/tests/test_locale_deprecations.py +0 -0
  193. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/tests/test_locale_getdefaultlocale_deprecation.py +0 -0
  194. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/tests/test_macpath_deprecations.py +0 -0
  195. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/tests/test_mailcap_migrations.py +0 -0
  196. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/tests/test_module_cached_attribute.py +0 -0
  197. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/tests/test_os_deprecations.py +0 -0
  198. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/tests/test_pathlib_deprecations.py +0 -0
  199. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/tests/test_pep594_migrations.py +0 -0
  200. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/tests/test_pep594_system_migrations.py +0 -0
  201. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/tests/test_pkgutil_deprecations.py +0 -0
  202. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/tests/test_platform_deprecations.py +0 -0
  203. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/tests/test_profile_deprecations.py +0 -0
  204. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/tests/test_pydantic_deprecations.py +0 -0
  205. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/tests/test_pydantic_fields.py +0 -0
  206. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/tests/test_pydantic_model_fields.py +0 -0
  207. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/tests/test_re_deprecations.py +0 -0
  208. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/tests/test_recipe_conventions.py +0 -0
  209. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/tests/test_recipe_reachability.py +0 -0
  210. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/tests/test_removed_modules_312.py +0 -0
  211. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/tests/test_shutil_deprecations.py +0 -0
  212. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/tests/test_socket_deprecations.py +0 -0
  213. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/tests/test_sre_migrations.py +0 -0
  214. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/tests/test_ssl_deprecations.py +0 -0
  215. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/tests/test_string_formatting.py +0 -0
  216. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/tests/test_sys_deprecations.py +0 -0
  217. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/tests/test_sys_last_deprecations.py +0 -0
  218. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/tests/test_tarfile_deprecations.py +0 -0
  219. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/tests/test_tempfile_deprecations.py +0 -0
  220. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/tests/test_text_encoding.py +0 -0
  221. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/tests/test_threading_deprecations.py +0 -0
  222. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/tests/test_threading_extended.py +0 -0
  223. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/tests/test_threading_is_alive_deprecation.py +0 -0
  224. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/tests/test_types_deprecations.py +0 -0
  225. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/tests/test_typing_alias_moves.py +0 -0
  226. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/tests/test_typing_callable.py +0 -0
  227. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/tests/test_typing_deprecations.py +0 -0
  228. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/tests/test_typing_functional_syntax.py +0 -0
  229. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/tests/test_typing_union_to_pipe.py +0 -0
  230. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/tests/test_unittest_deprecations.py +0 -0
  231. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/tests/test_upgrade_to_pydantic.py +0 -0
  232. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/tests/test_urllib_deprecations.py +0 -0
  233. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/tests/test_wave_deprecations.py +0 -0
  234. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/tests/test_webbrowser_deprecations.py +0 -0
  235. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/tests/test_xdrlib_migrations.py +0 -0
  236. {openrewrite_migrate_python-0.20.0 → openrewrite_migrate_python-0.22.0}/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.20.0
3
+ Version: 0.22.0
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.20.0" # Updated dynamically during release
8
+ version = "0.22.0" # 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"
@@ -73,6 +73,7 @@ from .locale_deprecations import ReplaceLocaleResetlocale
73
73
  from .locale_getdefaultlocale_deprecation import FindLocaleGetdefaultlocale
74
74
  from .macpath_deprecations import FindMacpathModule
75
75
  from .mailcap_migrations import FindMailcapModule
76
+ from .mock_assertions import AddMockAssertPrefix
76
77
  from .module_cached_attribute import ReplaceModuleCachedAttribute
77
78
  from .nntplib_migrations import FindNntplibModule
78
79
  from .os_deprecations import FindOsPopen, FindOsSpawn
@@ -85,7 +86,7 @@ from .pep594_system_migrations import (
85
86
  FindOssaudiodevModule,
86
87
  FindSpwdModule,
87
88
  )
88
- from .pipes_migrations import FindPipesModule
89
+ from .pipes_migrations import FindPipesModule, ReplacePipesQuote
89
90
  from .pkgutil_deprecations import ReplacePkgutilFindLoader, ReplacePkgutilGetLoader
90
91
  from .profile_deprecations import FindProfileModule
91
92
  from .pydantic_deprecations import (
@@ -192,6 +193,7 @@ __all__ = [
192
193
  "FindInspectGetargspec",
193
194
  "FindMacpathModule",
194
195
  "FindMailcapModule",
196
+ "AddMockAssertPrefix",
195
197
  "FindMsilibModule",
196
198
  "FindNisModule",
197
199
  "FindNntplibModule",
@@ -201,6 +203,7 @@ __all__ = [
201
203
  "FindOssaudiodevModule",
202
204
  "FindPathlibLinkTo",
203
205
  "FindPipesModule",
206
+ "ReplacePipesQuote",
204
207
  "ReplacePlatformPopen",
205
208
  "ReplaceReTemplate",
206
209
  "FindRemovedModules312",
@@ -2,13 +2,14 @@
2
2
  Recipes for migrating deprecated datetime.utcnow() and datetime.utcfromtimestamp() calls.
3
3
 
4
4
  These methods are deprecated in Python 3.12+ because they return naive datetime objects
5
- that don't carry timezone information. The recommended replacements are:
5
+ that don't carry timezone information. The replacements return the same naive value:
6
6
 
7
- - datetime.utcnow() -> datetime.now(UTC)
8
- - datetime.utcfromtimestamp(ts) -> datetime.fromtimestamp(ts, UTC)
7
+ - datetime.utcnow() -> datetime.now(UTC).replace(tzinfo=None)
8
+ - datetime.utcfromtimestamp(ts) -> datetime.fromtimestamp(ts, UTC).replace(tzinfo=None)
9
9
 
10
- The replacements are timezone-aware where the deprecated calls were naive, so values already
11
- stored or compared as naive UTC need migrating alongside the call sites.
10
+ An aware result never equals a naive datetime, raises ``TypeError`` when ordered against or
11
+ subtracted from one, and prints with a ``+00:00`` offset. Making the values aware is a change
12
+ of its own, not part of the upgrade.
12
13
 
13
14
  See: https://docs.python.org/3/library/datetime.html#datetime.datetime.utcnow
14
15
  """
@@ -56,18 +57,18 @@ _DATETIME_MODULE = ("datetime", None)
56
57
 
57
58
  @lru_cache(maxsize=None)
58
59
  def _now_template(utc: str) -> Template:
59
- return template(f"{_sel}.now({raw(utc)})")
60
+ return template(f"{_sel}.now({raw(utc)}).replace(tzinfo=None)")
60
61
 
61
62
 
62
63
  @lru_cache(maxsize=None)
63
64
  def _fromtimestamp_template(utc: str) -> Template:
64
- return template(f"{_sel}.fromtimestamp({_ts}, {raw(utc)})")
65
+ return template(f"{_sel}.fromtimestamp({_ts}, {raw(utc)}).replace(tzinfo=None)")
65
66
 
66
67
 
67
68
  class _DatetimeUtcVisitor(PythonVisitor[ExecutionContext]):
68
- """Rewrites a naive UTC constructor to its aware counterpart, spelling UTC the way the
69
- file's own ``datetime`` imports allow. Those imports also identify the receiver, which a
70
- parse that attributes no types still supplies.
69
+ """Rewrites a deprecated naive UTC constructor to its aware counterpart made naive again,
70
+ spelling UTC the way the file's own ``datetime`` imports allow. Those imports also
71
+ identify the receiver, which a parse that attributes no types still supplies.
71
72
  """
72
73
 
73
74
  _target = ""
@@ -131,7 +132,7 @@ class _DatetimeUtcVisitor(PythonVisitor[ExecutionContext]):
131
132
  @categorize(_Python312)
132
133
  class ReplaceDatetimeUtcNow(Recipe):
133
134
  """
134
- Replace ``datetime.utcnow()`` with ``datetime.now(UTC)``.
135
+ Replace ``datetime.utcnow()`` with ``datetime.now(UTC).replace(tzinfo=None)``.
135
136
 
136
137
  The ``datetime.utcnow()`` method is deprecated in Python 3.12 because it returns
137
138
  a naive datetime object that doesn't carry timezone information. This can lead
@@ -144,7 +145,7 @@ class ReplaceDatetimeUtcNow(Recipe):
144
145
 
145
146
  After:
146
147
  from datetime import datetime, UTC
147
- now = datetime.now(UTC)
148
+ now = datetime.now(UTC).replace(tzinfo=None)
148
149
  """
149
150
 
150
151
  @property
@@ -153,15 +154,15 @@ class ReplaceDatetimeUtcNow(Recipe):
153
154
 
154
155
  @property
155
156
  def display_name(self) -> str:
156
- return "Replace `datetime.utcnow()` with `datetime.now(UTC)`"
157
+ return "Replace `datetime.utcnow()` with `datetime.now(UTC).replace(tzinfo=None)`"
157
158
 
158
159
  @property
159
160
  def description(self) -> str:
160
161
  return (
161
162
  "The `datetime.utcnow()` method is deprecated in Python 3.12. "
162
- "Replace it with `datetime.now(UTC)`, importing `UTC` from `datetime` where the "
163
- "name is not already in scope. The result is timezone-aware where `utcnow()` was "
164
- "naive, so stored or compared values may need migrating alongside the call sites."
163
+ "Replace it with `datetime.now(UTC).replace(tzinfo=None)`, importing `UTC` from "
164
+ "`datetime` where the name is not already in scope. The result is the naive UTC "
165
+ "datetime `utcnow()` returned, so it still compares with other naive values."
165
166
  )
166
167
 
167
168
  @property
@@ -193,7 +194,8 @@ class ReplaceDatetimeUtcNow(Recipe):
193
194
  @categorize(_Python312)
194
195
  class ReplaceDatetimeUtcFromTimestamp(Recipe):
195
196
  """
196
- Replace ``datetime.utcfromtimestamp(ts)`` with ``datetime.fromtimestamp(ts, UTC)``.
197
+ Replace ``datetime.utcfromtimestamp(ts)`` with
198
+ ``datetime.fromtimestamp(ts, UTC).replace(tzinfo=None)``.
197
199
 
198
200
  The ``datetime.utcfromtimestamp()`` method is deprecated in Python 3.12 because it
199
201
  returns a naive datetime object.
@@ -205,7 +207,7 @@ class ReplaceDatetimeUtcFromTimestamp(Recipe):
205
207
 
206
208
  After:
207
209
  from datetime import datetime, UTC
208
- dt = datetime.fromtimestamp(1234567890, UTC)
210
+ dt = datetime.fromtimestamp(1234567890, UTC).replace(tzinfo=None)
209
211
  """
210
212
 
211
213
  @property
@@ -214,16 +216,16 @@ class ReplaceDatetimeUtcFromTimestamp(Recipe):
214
216
 
215
217
  @property
216
218
  def display_name(self) -> str:
217
- return "Replace `datetime.utcfromtimestamp()` with `datetime.fromtimestamp(ts, UTC)`"
219
+ return "Replace `datetime.utcfromtimestamp()` with `datetime.fromtimestamp(ts, UTC).replace(tzinfo=None)`"
218
220
 
219
221
  @property
220
222
  def description(self) -> str:
221
223
  return (
222
224
  "The `datetime.utcfromtimestamp()` method is deprecated in Python 3.12. "
223
- "Replace it with `datetime.fromtimestamp(ts, UTC)`, importing `UTC` from "
224
- "`datetime` where the name is not already in scope. The result is timezone-aware "
225
- "where `utcfromtimestamp()` was naive, so stored or compared values may need "
226
- "migrating alongside the call sites."
225
+ "Replace it with `datetime.fromtimestamp(ts, UTC).replace(tzinfo=None)`, importing "
226
+ "`UTC` from `datetime` where the name is not already in scope. The result is the "
227
+ "naive UTC datetime `utcfromtimestamp()` returned, so it still compares with other "
228
+ "naive values."
227
229
  )
228
230
 
229
231
  @property
@@ -0,0 +1,117 @@
1
+ """
2
+ Recipes for mock assertions that Python 3.12 rejects.
3
+
4
+ See: https://docs.python.org/3/whatsnew/3.12.html
5
+ """
6
+
7
+ from typing import Any, List
8
+
9
+ from rewrite import ExecutionContext, Preconditions, Recipe, TreeVisitor
10
+ from rewrite.category import CategoryDescriptor
11
+ from rewrite.decorators import categorize
12
+ from rewrite.marketplace import Python
13
+ from rewrite.java.support_types import JavaType, Space
14
+ from rewrite.java.tree import Assert, Block, J, MethodInvocation
15
+ from rewrite.python.preconditions import uses_method
16
+ from rewrite.python.type_utils import is_of_type_with_name
17
+ from rewrite.python.visitor import PythonVisitor
18
+
19
+ from openrewrite_code_quality_python.codequality._trivia import has_comments
20
+
21
+ _Python312 = [
22
+ *Python,
23
+ CategoryDescriptor(display_name="Migrate"),
24
+ CategoryDescriptor(display_name="Python 3.12"),
25
+ ]
26
+
27
+ # `called` is a property, so a mock still answers it.
28
+ _UNPREFIXED = ("called_once", "called_with", "called_once_with", "any_call", "has_calls", "not_called")
29
+
30
+
31
+ def _is_unprefixed_mock_call(tree: Any) -> bool:
32
+ if not isinstance(tree, MethodInvocation) or tree.select is None:
33
+ return False
34
+ if tree.name.simple_name not in _UNPREFIXED:
35
+ return False
36
+ # A mock stored on `self` in `setUp()` has no type the parser sees.
37
+ receiver = tree.select.type
38
+ return isinstance(receiver, JavaType.Unknown) or is_of_type_with_name(
39
+ receiver, True, lambda n: n.startswith(("unittest.mock.", "mock."))
40
+ )
41
+
42
+
43
+ def _prefixed(call: MethodInvocation, prefix: Space) -> MethodInvocation:
44
+ return call.replace(
45
+ _prefix=prefix,
46
+ _name=call.name.replace(_simple_name=f"assert_{call.name.simple_name}", _type=None, _field_type=None),
47
+ _method_type=None,
48
+ )
49
+
50
+
51
+ @categorize(_Python312)
52
+ class AddMockAssertPrefix(Recipe):
53
+ """
54
+ Add the ``assert_`` prefix to mock assertions that lack it.
55
+
56
+ Example:
57
+ Before:
58
+ def test_cleanup(self):
59
+ self.callback.called_once_with(42)
60
+
61
+ After:
62
+ def test_cleanup(self):
63
+ self.callback.assert_called_once_with(42)
64
+ """
65
+
66
+ @property
67
+ def name(self) -> str:
68
+ return "org.openrewrite.python.migrate.AddMockAssertPrefix"
69
+
70
+ @property
71
+ def display_name(self) -> str:
72
+ return "Add the `assert_` prefix to mock assertions that lack it"
73
+
74
+ @property
75
+ def description(self) -> str:
76
+ return (
77
+ "Since Python 3.12 a mock raises `AttributeError` for `called_once_with()` and the "
78
+ "other assertion names without their `assert_` prefix. Before, such a call asserted "
79
+ "nothing. The prefix is added where the call is a statement of its own inside a "
80
+ "function, the whole condition of an `assert` without a message, or the only argument "
81
+ "of `assertTrue()`. The recipe matches the method name, and leaves a receiver whose "
82
+ "type resolves to a class other than a mock. A test that passed only because nothing "
83
+ "was asserted fails once it asserts."
84
+ )
85
+
86
+ @property
87
+ def tags(self) -> List[str]:
88
+ return ["python", "migration", "3.12", "unittest"]
89
+
90
+ def editor(self) -> TreeVisitor[Any, ExecutionContext]:
91
+ class Visitor(PythonVisitor[ExecutionContext]):
92
+ def visit_method_invocation(self, method: MethodInvocation, p: ExecutionContext) -> J:
93
+ m = super().visit_method_invocation(method, p)
94
+ if not isinstance(m, MethodInvocation) or not isinstance(
95
+ self.cursor.parent_tree_cursor().value, Block
96
+ ):
97
+ return m
98
+ if _is_unprefixed_mock_call(m):
99
+ return _prefixed(m, m.prefix)
100
+ if m.name.simple_name != "assertTrue" or len(m.arguments) != 1:
101
+ return m
102
+ return self._replace_check(m, m.arguments[0])
103
+
104
+ def visit_assert(self, assert_: Assert, p: ExecutionContext) -> J:
105
+ a = super().visit_assert(assert_, p)
106
+ if not isinstance(a, Assert) or a.detail is not None:
107
+ return a
108
+ return self._replace_check(a, a.condition)
109
+
110
+ def _replace_check(self, check: J, condition: Any) -> J:
111
+ if not _is_unprefixed_mock_call(condition) or has_comments(check.replace(_prefix=Space.EMPTY)):
112
+ return check
113
+ return _prefixed(condition, check.prefix)
114
+
115
+ # A gate naming a mock type would drop the unknown receivers the visitor accepts.
116
+ gate = Preconditions.or_(*(uses_method(f"*..* {name}(..)") for name in _UNPREFIXED))
117
+ return Preconditions.check(gate, Visitor())
@@ -17,6 +17,7 @@ from rewrite import ExecutionContext, Recipe, TreeVisitor
17
17
  from rewrite.category import CategoryDescriptor
18
18
  from rewrite.decorators import categorize
19
19
  from rewrite.marketplace import Python
20
+ from rewrite.python.recipes import ChangeImport
20
21
  from ._module_imports import find_module_imports
21
22
 
22
23
  # Define category path: Python > Migrate > Python 3.13
@@ -27,6 +28,46 @@ _Python313 = [
27
28
  ]
28
29
 
29
30
 
31
+ @categorize(_Python313)
32
+ class ReplacePipesQuote(Recipe):
33
+ """
34
+ Replace ``pipes.quote()`` with ``shlex.quote()``.
35
+
36
+ ``pipes.quote`` is ``shlex.quote`` re-exported, and the ``pipes`` module was removed in
37
+ Python 3.13.
38
+
39
+ Example:
40
+ Before:
41
+ import pipes
42
+ quoted = pipes.quote(path)
43
+
44
+ After:
45
+ import shlex
46
+ quoted = shlex.quote(path)
47
+ """
48
+
49
+ @property
50
+ def name(self) -> str:
51
+ return "org.openrewrite.python.migrate.ReplacePipesQuote"
52
+
53
+ @property
54
+ def display_name(self) -> str:
55
+ return "Replace `pipes.quote()` with `shlex.quote()`"
56
+
57
+ @property
58
+ def description(self) -> str:
59
+ return (
60
+ "`pipes.quote()` is `shlex.quote()` under another name, and the `pipes` module was "
61
+ "removed in Python 3.13. The `pipes` import stays where the file uses another of its "
62
+ "members."
63
+ )
64
+
65
+ @property
66
+ def tags(self) -> List[str]:
67
+ return ["python", "migration", "3.13", "PEP 594", "pipes"]
68
+
69
+ def recipe_list(self) -> List[Recipe]:
70
+ return [ChangeImport(old_module="pipes", old_name="quote", new_module="shlex")]
30
71
 
31
72
 
32
73
  @categorize(_Python313)
@@ -62,6 +62,7 @@ class UpgradeToPython312(Recipe):
62
62
  from .distutils_deprecations import FindDistutilsUsage
63
63
  from .distutils_migrations import ReplaceDistutilsVersion
64
64
  from .imp_migrations import FindImpUsage
65
+ from .mock_assertions import AddMockAssertPrefix
65
66
  from .os_deprecations import FindOsPopen, FindOsSpawn
66
67
  from .pathlib_deprecations import FindPathlibLinkTo
67
68
  from .pkgutil_deprecations import ReplacePkgutilFindLoader, ReplacePkgutilGetLoader
@@ -101,6 +102,8 @@ class UpgradeToPython312(Recipe):
101
102
  FindShutilRmtreeOnerror(),
102
103
  # sys.last_type/last_value/last_traceback -> sys.last_exc
103
104
  ReplaceSysLastExcInfo(),
105
+ # Mocks reject `called_once_with()` and the other unprefixed assertion names since 3.12
106
+ AddMockAssertPrefix(),
104
107
  # Deprecated in 3.12, removed in 3.16 and 3.17
105
108
  ReplaceBitwiseInversionOnBool(),
106
109
  FindBitwiseInversionOnBool(),
@@ -80,7 +80,7 @@ class UpgradeToPython313(Recipe):
80
80
  FindOssaudiodevModule,
81
81
  FindSpwdModule,
82
82
  )
83
- from .pipes_migrations import FindPipesModule
83
+ from .pipes_migrations import FindPipesModule, ReplacePipesQuote
84
84
  from .telnetlib_migrations import FindTelnetlibModule
85
85
  from .upgrade_to_python312 import UpgradeToPython312
86
86
  from .uu_migrations import FindUuModule
@@ -91,6 +91,8 @@ class UpgradeToPython313(Recipe):
91
91
  UpgradeToPython312(),
92
92
  # locale.resetlocale() removed in 3.13 (deprecated in 3.11)
93
93
  ReplaceLocaleResetlocale(),
94
+ # Before FindPipesModule, which then marks only the imports still needed
95
+ ReplacePipesQuote(),
94
96
  # PEP 594 "dead batteries" - removed modules (detection only)
95
97
  FindAifcModule(),
96
98
  FindAudioopModule(),
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: openrewrite-migrate-python
3
- Version: 0.20.0
3
+ Version: 0.22.0
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
@@ -101,6 +101,7 @@ src/openrewrite_migrate_python/migrate/locale_deprecations.py
101
101
  src/openrewrite_migrate_python/migrate/locale_getdefaultlocale_deprecation.py
102
102
  src/openrewrite_migrate_python/migrate/macpath_deprecations.py
103
103
  src/openrewrite_migrate_python/migrate/mailcap_migrations.py
104
+ src/openrewrite_migrate_python/migrate/mock_assertions.py
104
105
  src/openrewrite_migrate_python/migrate/module_cached_attribute.py
105
106
  src/openrewrite_migrate_python/migrate/nntplib_migrations.py
106
107
  src/openrewrite_migrate_python/migrate/os_deprecations.py
@@ -187,11 +188,13 @@ tests/test_locale_deprecations.py
187
188
  tests/test_locale_getdefaultlocale_deprecation.py
188
189
  tests/test_macpath_deprecations.py
189
190
  tests/test_mailcap_migrations.py
191
+ tests/test_mock_assertions.py
190
192
  tests/test_module_cached_attribute.py
191
193
  tests/test_os_deprecations.py
192
194
  tests/test_pathlib_deprecations.py
193
195
  tests/test_pep594_migrations.py
194
196
  tests/test_pep594_system_migrations.py
197
+ tests/test_pipes_migrations.py
195
198
  tests/test_pkgutil_deprecations.py
196
199
  tests/test_platform_deprecations.py
197
200
  tests/test_profile_deprecations.py
@@ -22,7 +22,7 @@ class TestReplaceDatetimeUtcNow:
22
22
  """,
23
23
  """
24
24
  from datetime import datetime, UTC
25
- now = datetime.now(UTC)
25
+ now = datetime.now(UTC).replace(tzinfo=None)
26
26
  """,
27
27
  )
28
28
  )
@@ -41,7 +41,7 @@ class TestReplaceDatetimeUtcNow:
41
41
  from datetime import datetime, UTC
42
42
  now = datetime.utcnow( # wall clock
43
43
  )
44
- later = datetime.now(UTC)
44
+ later = datetime.now(UTC).replace(tzinfo=None)
45
45
  """,
46
46
  )
47
47
  )
@@ -57,7 +57,7 @@ class TestReplaceDatetimeUtcNow:
57
57
  """,
58
58
  """
59
59
  from datetime import datetime, timezone
60
- now = datetime.now(timezone.utc)
60
+ now = datetime.now(timezone.utc).replace(tzinfo=None)
61
61
  """,
62
62
  )
63
63
  )
@@ -73,7 +73,7 @@ class TestReplaceDatetimeUtcNow:
73
73
  """,
74
74
  """
75
75
  import datetime
76
- now = datetime.datetime.now(datetime.UTC)
76
+ now = datetime.datetime.now(datetime.UTC).replace(tzinfo=None)
77
77
  """,
78
78
  )
79
79
  )
@@ -96,7 +96,7 @@ class TestReplaceDatetimeUtcNow:
96
96
  class Job:
97
97
  started: datetime.datetime
98
98
  def restart(self):
99
- return self.started.now(UTC)
99
+ return self.started.now(UTC).replace(tzinfo=None)
100
100
  """,
101
101
  )
102
102
  )
@@ -111,7 +111,7 @@ class TestReplaceDatetimeUtcNow:
111
111
  """,
112
112
  """
113
113
  from datetime import datetime as dt, UTC
114
- now = dt.now(UTC)
114
+ now = dt.now(UTC).replace(tzinfo=None)
115
115
  """,
116
116
  )
117
117
  )
@@ -131,7 +131,7 @@ class TestReplaceDatetimeUtcNow:
131
131
  from datetime import datetime, timezone
132
132
  from pytz import UTC
133
133
 
134
- now = datetime.now(timezone.utc)
134
+ now = datetime.now(timezone.utc).replace(tzinfo=None)
135
135
  """,
136
136
  )
137
137
  )
@@ -155,7 +155,7 @@ class TestReplaceDatetimeUtcNow:
155
155
 
156
156
  def stamp():
157
157
  UTC = "Z"
158
- return UTC, datetime.now(timezone.utc)
158
+ return UTC, datetime.now(timezone.utc).replace(tzinfo=None)
159
159
  """,
160
160
  )
161
161
  )
@@ -191,7 +191,7 @@ class TestReplaceDatetimeUtcNow:
191
191
  def cutoff(max_age):
192
192
  from datetime import datetime, timedelta
193
193
 
194
- return datetime.now(UTC) - timedelta(seconds=max_age)
194
+ return datetime.now(UTC).replace(tzinfo=None) - timedelta(seconds=max_age)
195
195
  """,
196
196
  )
197
197
  )
@@ -225,7 +225,7 @@ class TestReplaceDatetimeUtcNow:
225
225
  from datetime import datetime, UTC
226
226
  class Stamp(datetime):
227
227
  pass
228
- now = Stamp.now(UTC)
228
+ now = Stamp.now(UTC).replace(tzinfo=None)
229
229
  """,
230
230
  )
231
231
  )
@@ -275,7 +275,7 @@ class TestReplaceDatetimeUtcNow:
275
275
 
276
276
  obj = MyClass()
277
277
  result = obj.utcnow()
278
- now = datetime.now(UTC)
278
+ now = datetime.now(UTC).replace(tzinfo=None)
279
279
  """,
280
280
  )
281
281
  )
@@ -283,7 +283,7 @@ class TestReplaceDatetimeUtcNow:
283
283
  class TestReplaceDatetimeUtcFromTimestamp:
284
284
  """Tests for the ReplaceDatetimeUtcFromTimestamp recipe."""
285
285
 
286
- def test_appends_utc_argument(self):
286
+ def test_appends_utc_and_keeps_the_result_naive(self):
287
287
  spec = RecipeSpec(recipe=ReplaceDatetimeUtcFromTimestamp())
288
288
  spec.rewrite_run(
289
289
  python(
@@ -293,7 +293,7 @@ class TestReplaceDatetimeUtcFromTimestamp:
293
293
  """,
294
294
  """
295
295
  from datetime import datetime, UTC
296
- dt = datetime.fromtimestamp(1234567890, UTC)
296
+ dt = datetime.fromtimestamp(1234567890, UTC).replace(tzinfo=None)
297
297
  """,
298
298
  )
299
299
  )
@@ -312,7 +312,7 @@ class TestReplaceDatetimeUtcFromTimestamp:
312
312
  from datetime import datetime, UTC
313
313
  dt = datetime.utcfromtimestamp(ts # epoch
314
314
  )
315
- other = datetime.fromtimestamp(ts, UTC)
315
+ other = datetime.fromtimestamp(ts, UTC).replace(tzinfo=None)
316
316
  """,
317
317
  )
318
318
  )
@@ -0,0 +1,86 @@
1
+ from rewrite.test import RecipeSpec, python
2
+
3
+ from openrewrite_migrate_python.migrate.mock_assertions import AddMockAssertPrefix
4
+ from tests._after_recipe import assert_idempotent_and_parse_shape
5
+
6
+ _check = assert_idempotent_and_parse_shape(AddMockAssertPrefix())
7
+
8
+
9
+ class TestAddMockAssertPrefix:
10
+
11
+ def test_prefixes_a_call_whose_result_is_discarded(self):
12
+ RecipeSpec(recipe=AddMockAssertPrefix()).rewrite_run(
13
+ python(
14
+ """
15
+ from unittest.mock import Mock
16
+
17
+ def test_writes(self):
18
+ m = Mock()
19
+ m.called_once_with(1)
20
+ self.popen.stdin.has_calls([])
21
+ """,
22
+ """
23
+ from unittest.mock import Mock
24
+
25
+ def test_writes(self):
26
+ m = Mock()
27
+ m.assert_called_once_with(1)
28
+ self.popen.stdin.assert_has_calls([])
29
+ """,
30
+ after_recipe=_check,
31
+ )
32
+ )
33
+
34
+ def test_replaces_a_truth_assertion_of_the_call(self):
35
+ RecipeSpec(recipe=AddMockAssertPrefix()).rewrite_run(
36
+ python(
37
+ """
38
+ import unittest
39
+
40
+ class T(unittest.TestCase):
41
+ def test_cleanup(self):
42
+ assert self.callback.called_with(42, keyword='value')
43
+ self.assertTrue(self.publisher.called_once())
44
+ """,
45
+ """
46
+ import unittest
47
+
48
+ class T(unittest.TestCase):
49
+ def test_cleanup(self):
50
+ self.callback.assert_called_with(42, keyword='value')
51
+ self.publisher.assert_called_once()
52
+ """,
53
+ after_recipe=_check,
54
+ )
55
+ )
56
+
57
+ def test_leaves_other_receivers_and_values_that_are_read(self):
58
+ RecipeSpec(recipe=AddMockAssertPrefix()).rewrite_run(
59
+ python(
60
+ """
61
+ class Recorder:
62
+ def has_calls(self, calls): ...
63
+
64
+ def test_kept(self):
65
+ Recorder().has_calls([])
66
+ results.append(self.m.any_call(1))
67
+ assert self.adapter.called_once # a requests_mock property
68
+ """
69
+ )
70
+ )
71
+
72
+ def test_keeps_a_check_whose_message_or_comment_would_be_lost(self):
73
+ RecipeSpec(recipe=AddMockAssertPrefix()).rewrite_run(
74
+ python(
75
+ """
76
+ import unittest
77
+
78
+ class T(unittest.TestCase):
79
+ def test_kept(self):
80
+ assert self.m.called_with(1), "not cleaned up"
81
+ self.assertTrue(self.m.called_once(), "not published")
82
+ self.assertTrue( # published once
83
+ self.m.called_once())
84
+ """
85
+ )
86
+ )