wexample-wex-addon-dev-python 15.8.1__tar.gz → 15.9.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 (121) hide show
  1. {wexample_wex_addon_dev_python-15.8.1 → wexample_wex_addon_dev_python-15.9.0}/PKG-INFO +3 -3
  2. {wexample_wex_addon_dev_python-15.8.1 → wexample_wex_addon_dev_python-15.9.0}/README.md +1 -1
  3. {wexample_wex_addon_dev_python-15.8.1 → wexample_wex_addon_dev_python-15.9.0}/pyproject.toml +2 -2
  4. {wexample_wex_addon_dev_python-15.8.1 → wexample_wex_addon_dev_python-15.9.0}/src/wexample_wex_addon_dev_python/workdir/python_package_workdir.py +56 -3
  5. wexample_wex_addon_dev_python-15.9.0/tests/unit/test_pypi_background_upload.py +47 -0
  6. {wexample_wex_addon_dev_python-15.8.1 → wexample_wex_addon_dev_python-15.9.0}/src/wexample_wex_addon_dev_python/__init__.py +0 -0
  7. {wexample_wex_addon_dev_python-15.8.1 → wexample_wex_addon_dev_python-15.9.0}/src/wexample_wex_addon_dev_python/commands/__init__.py +0 -0
  8. {wexample_wex_addon_dev_python-15.8.1 → wexample_wex_addon_dev_python-15.9.0}/src/wexample_wex_addon_dev_python/commands/code/__init__.py +0 -0
  9. {wexample_wex_addon_dev_python-15.8.1 → wexample_wex_addon_dev_python-15.9.0}/src/wexample_wex_addon_dev_python/commands/code/check/__init__.py +0 -0
  10. {wexample_wex_addon_dev_python-15.8.1 → wexample_wex_addon_dev_python-15.9.0}/src/wexample_wex_addon_dev_python/commands/code/check/mypy.py +0 -0
  11. {wexample_wex_addon_dev_python-15.8.1 → wexample_wex_addon_dev_python-15.9.0}/src/wexample_wex_addon_dev_python/commands/code/check/pylint.py +0 -0
  12. {wexample_wex_addon_dev_python-15.8.1 → wexample_wex_addon_dev_python-15.9.0}/src/wexample_wex_addon_dev_python/commands/code/check/pyright.py +0 -0
  13. {wexample_wex_addon_dev_python-15.8.1 → wexample_wex_addon_dev_python-15.9.0}/src/wexample_wex_addon_dev_python/commands/code/check.py +0 -0
  14. {wexample_wex_addon_dev_python-15.8.1 → wexample_wex_addon_dev_python-15.9.0}/src/wexample_wex_addon_dev_python/commands/code/format/__init__.py +0 -0
  15. {wexample_wex_addon_dev_python-15.8.1 → wexample_wex_addon_dev_python-15.9.0}/src/wexample_wex_addon_dev_python/commands/code/format/black.py +0 -0
  16. {wexample_wex_addon_dev_python-15.8.1 → wexample_wex_addon_dev_python-15.9.0}/src/wexample_wex_addon_dev_python/commands/code/format/isort.py +0 -0
  17. {wexample_wex_addon_dev_python-15.8.1 → wexample_wex_addon_dev_python-15.9.0}/src/wexample_wex_addon_dev_python/commands/code/format.py +0 -0
  18. {wexample_wex_addon_dev_python-15.8.1 → wexample_wex_addon_dev_python-15.9.0}/src/wexample_wex_addon_dev_python/commands/code/rename.py +0 -0
  19. {wexample_wex_addon_dev_python-15.8.1 → wexample_wex_addon_dev_python-15.9.0}/src/wexample_wex_addon_dev_python/commands/examples/__init__.py +0 -0
  20. {wexample_wex_addon_dev_python-15.8.1 → wexample_wex_addon_dev_python-15.9.0}/src/wexample_wex_addon_dev_python/commands/examples/utils/__init__.py +0 -0
  21. {wexample_wex_addon_dev_python-15.8.1 → wexample_wex_addon_dev_python-15.9.0}/src/wexample_wex_addon_dev_python/commands/examples/utils/some_example_type.py +0 -0
  22. {wexample_wex_addon_dev_python-15.8.1 → wexample_wex_addon_dev_python-15.9.0}/src/wexample_wex_addon_dev_python/commands/examples/validate.py +0 -0
  23. {wexample_wex_addon_dev_python-15.8.1 → wexample_wex_addon_dev_python-15.9.0}/src/wexample_wex_addon_dev_python/commands/release/__init__.py +0 -0
  24. {wexample_wex_addon_dev_python-15.8.1 → wexample_wex_addon_dev_python-15.9.0}/src/wexample_wex_addon_dev_python/common/__init__.py +0 -0
  25. {wexample_wex_addon_dev_python-15.8.1 → wexample_wex_addon_dev_python-15.9.0}/src/wexample_wex_addon_dev_python/common/pypi_registry_gateway.py +0 -0
  26. {wexample_wex_addon_dev_python-15.8.1 → wexample_wex_addon_dev_python-15.9.0}/src/wexample_wex_addon_dev_python/config_value/__init__.py +0 -0
  27. {wexample_wex_addon_dev_python-15.8.1 → wexample_wex_addon_dev_python-15.9.0}/src/wexample_wex_addon_dev_python/config_value/python_package_readme_config_value.py +0 -0
  28. {wexample_wex_addon_dev_python-15.8.1 → wexample_wex_addon_dev_python-15.9.0}/src/wexample_wex_addon_dev_python/const/__init__.py +0 -0
  29. {wexample_wex_addon_dev_python-15.8.1 → wexample_wex_addon_dev_python-15.9.0}/src/wexample_wex_addon_dev_python/const/package.py +0 -0
  30. {wexample_wex_addon_dev_python-15.8.1 → wexample_wex_addon_dev_python-15.9.0}/src/wexample_wex_addon_dev_python/const/python.py +0 -0
  31. {wexample_wex_addon_dev_python-15.8.1 → wexample_wex_addon_dev_python-15.9.0}/src/wexample_wex_addon_dev_python/const/tags.py +0 -0
  32. {wexample_wex_addon_dev_python-15.8.1 → wexample_wex_addon_dev_python-15.9.0}/src/wexample_wex_addon_dev_python/file/__init__.py +0 -0
  33. {wexample_wex_addon_dev_python-15.8.1 → wexample_wex_addon_dev_python-15.9.0}/src/wexample_wex_addon_dev_python/file/python_app_iml_file.py +0 -0
  34. {wexample_wex_addon_dev_python-15.8.1 → wexample_wex_addon_dev_python-15.9.0}/src/wexample_wex_addon_dev_python/file/python_pyproject_toml_file.py +0 -0
  35. {wexample_wex_addon_dev_python-15.8.1 → wexample_wex_addon_dev_python-15.9.0}/src/wexample_wex_addon_dev_python/formatter/__init__.py +0 -0
  36. {wexample_wex_addon_dev_python-15.8.1 → wexample_wex_addon_dev_python-15.9.0}/src/wexample_wex_addon_dev_python/formatter/python_code_formatter.py +0 -0
  37. {wexample_wex_addon_dev_python-15.8.1 → wexample_wex_addon_dev_python-15.9.0}/src/wexample_wex_addon_dev_python/helper/__init__.py +0 -0
  38. {wexample_wex_addon_dev_python-15.8.1 → wexample_wex_addon_dev_python-15.9.0}/src/wexample_wex_addon_dev_python/helper/pdm.py +0 -0
  39. {wexample_wex_addon_dev_python-15.8.1 → wexample_wex_addon_dev_python-15.9.0}/src/wexample_wex_addon_dev_python/middleware/__init__.py +0 -0
  40. {wexample_wex_addon_dev_python-15.8.1 → wexample_wex_addon_dev_python-15.9.0}/src/wexample_wex_addon_dev_python/middleware/each_python_file_middleware.py +0 -0
  41. {wexample_wex_addon_dev_python-15.8.1 → wexample_wex_addon_dev_python-15.9.0}/src/wexample_wex_addon_dev_python/py.typed +0 -0
  42. {wexample_wex_addon_dev_python-15.8.1 → wexample_wex_addon_dev_python-15.9.0}/src/wexample_wex_addon_dev_python/python_addon_manager.py +0 -0
  43. {wexample_wex_addon_dev_python-15.8.1 → wexample_wex_addon_dev_python-15.9.0}/src/wexample_wex_addon_dev_python/refactor/__init__.py +0 -0
  44. {wexample_wex_addon_dev_python-15.8.1 → wexample_wex_addon_dev_python-15.9.0}/src/wexample_wex_addon_dev_python/refactor/abstract_python_path_rename_handler.py +0 -0
  45. {wexample_wex_addon_dev_python-15.8.1 → wexample_wex_addon_dev_python-15.9.0}/src/wexample_wex_addon_dev_python/refactor/abstract_python_rename_handler.py +0 -0
  46. {wexample_wex_addon_dev_python-15.8.1 → wexample_wex_addon_dev_python-15.9.0}/src/wexample_wex_addon_dev_python/refactor/abstract_python_symbol_rename_handler.py +0 -0
  47. {wexample_wex_addon_dev_python-15.8.1 → wexample_wex_addon_dev_python-15.9.0}/src/wexample_wex_addon_dev_python/refactor/applier.py +0 -0
  48. {wexample_wex_addon_dev_python-15.8.1 → wexample_wex_addon_dev_python-15.9.0}/src/wexample_wex_addon_dev_python/refactor/python_class_rename_handler.py +0 -0
  49. {wexample_wex_addon_dev_python-15.8.1 → wexample_wex_addon_dev_python-15.9.0}/src/wexample_wex_addon_dev_python/refactor/python_common.py +0 -0
  50. {wexample_wex_addon_dev_python-15.8.1 → wexample_wex_addon_dev_python-15.9.0}/src/wexample_wex_addon_dev_python/refactor/python_constant_rename_handler.py +0 -0
  51. {wexample_wex_addon_dev_python-15.8.1 → wexample_wex_addon_dev_python-15.9.0}/src/wexample_wex_addon_dev_python/refactor/python_function_rename_handler.py +0 -0
  52. {wexample_wex_addon_dev_python-15.8.1 → wexample_wex_addon_dev_python-15.9.0}/src/wexample_wex_addon_dev_python/refactor/python_module_rename_handler.py +0 -0
  53. {wexample_wex_addon_dev_python-15.8.1 → wexample_wex_addon_dev_python-15.9.0}/src/wexample_wex_addon_dev_python/refactor/python_package_rename_handler.py +0 -0
  54. {wexample_wex_addon_dev_python-15.8.1 → wexample_wex_addon_dev_python-15.9.0}/src/wexample_wex_addon_dev_python/refactor/rename_plan.py +0 -0
  55. {wexample_wex_addon_dev_python-15.8.1 → wexample_wex_addon_dev_python-15.9.0}/src/wexample_wex_addon_dev_python/refactor/symbol_kind.py +0 -0
  56. {wexample_wex_addon_dev_python-15.8.1 → wexample_wex_addon_dev_python-15.9.0}/src/wexample_wex_addon_dev_python/resources/.wex.yml +0 -0
  57. {wexample_wex_addon_dev_python-15.8.1 → wexample_wex_addon_dev_python-15.9.0}/src/wexample_wex_addon_dev_python/resources/ai/agents/describer/agent.yml +0 -0
  58. {wexample_wex_addon_dev_python-15.8.1 → wexample_wex_addon_dev_python-15.9.0}/src/wexample_wex_addon_dev_python/resources/ai/agents/describer/context.j2 +0 -0
  59. {wexample_wex_addon_dev_python-15.8.1 → wexample_wex_addon_dev_python-15.9.0}/src/wexample_wex_addon_dev_python/resources/design_rules/python_code.md +0 -0
  60. {wexample_wex_addon_dev_python-15.8.1 → wexample_wex_addon_dev_python-15.9.0}/src/wexample_wex_addon_dev_python/resources/docker/Dockerfile.python-profiling +0 -0
  61. {wexample_wex_addon_dev_python-15.8.1 → wexample_wex_addon_dev_python-15.9.0}/src/wexample_wex_addon_dev_python/resources/package_gitlab_ci.yml +0 -0
  62. {wexample_wex_addon_dev_python-15.8.1 → wexample_wex_addon_dev_python-15.9.0}/src/wexample_wex_addon_dev_python/resources/package_publish_gitlab.yml +0 -0
  63. {wexample_wex_addon_dev_python-15.8.1 → wexample_wex_addon_dev_python-15.9.0}/src/wexample_wex_addon_dev_python/resources/readme_templates/install.md.j2 +0 -0
  64. {wexample_wex_addon_dev_python-15.8.1 → wexample_wex_addon_dev_python-15.9.0}/src/wexample_wex_addon_dev_python/resources/readme_templates/tests.md.j2 +0 -0
  65. {wexample_wex_addon_dev_python-15.8.1 → wexample_wex_addon_dev_python-15.9.0}/src/wexample_wex_addon_dev_python/resources/writing_rules/python_code.md +0 -0
  66. {wexample_wex_addon_dev_python-15.8.1 → wexample_wex_addon_dev_python-15.9.0}/src/wexample_wex_addon_dev_python/selection/__init__.py +0 -0
  67. {wexample_wex_addon_dev_python-15.8.1 → wexample_wex_addon_dev_python-15.9.0}/src/wexample_wex_addon_dev_python/selection/abstract_python_code_selection.py +0 -0
  68. {wexample_wex_addon_dev_python-15.8.1 → wexample_wex_addon_dev_python-15.9.0}/src/wexample_wex_addon_dev_python/selection/package_description_missing_selection.py +0 -0
  69. {wexample_wex_addon_dev_python-15.8.1 → wexample_wex_addon_dev_python-15.9.0}/src/wexample_wex_addon_dev_python/selection/python_code_performance_selection.py +0 -0
  70. {wexample_wex_addon_dev_python-15.8.1 → wexample_wex_addon_dev_python-15.9.0}/src/wexample_wex_addon_dev_python/services/__init__.py +0 -0
  71. {wexample_wex_addon_dev_python-15.8.1 → wexample_wex_addon_dev_python-15.9.0}/src/wexample_wex_addon_dev_python/services/python/__init__.py +0 -0
  72. {wexample_wex_addon_dev_python-15.8.1 → wexample_wex_addon_dev_python-15.9.0}/src/wexample_wex_addon_dev_python/services/python/app_service.py +0 -0
  73. {wexample_wex_addon_dev_python-15.8.1 → wexample_wex_addon_dev_python-15.9.0}/src/wexample_wex_addon_dev_python/services/python/commands/__init__.py +0 -0
  74. {wexample_wex_addon_dev_python-15.8.1 → wexample_wex_addon_dev_python-15.9.0}/src/wexample_wex_addon_dev_python/services/python/commands/service/__init__.py +0 -0
  75. {wexample_wex_addon_dev_python-15.8.1 → wexample_wex_addon_dev_python-15.9.0}/src/wexample_wex_addon_dev_python/services/python/commands/service/install.py +0 -0
  76. {wexample_wex_addon_dev_python-15.8.1 → wexample_wex_addon_dev_python-15.9.0}/src/wexample_wex_addon_dev_python/services/python/commands/service/setup.py +0 -0
  77. {wexample_wex_addon_dev_python-15.8.1 → wexample_wex_addon_dev_python-15.9.0}/src/wexample_wex_addon_dev_python/services/python/docker/.wex.yml +0 -0
  78. {wexample_wex_addon_dev_python-15.8.1 → wexample_wex_addon_dev_python-15.9.0}/src/wexample_wex_addon_dev_python/services/python/docker/docker-compose.yml +0 -0
  79. {wexample_wex_addon_dev_python-15.8.1 → wexample_wex_addon_dev_python-15.9.0}/src/wexample_wex_addon_dev_python/services/python/samples/__init__.py +0 -0
  80. {wexample_wex_addon_dev_python-15.8.1 → wexample_wex_addon_dev_python-15.9.0}/src/wexample_wex_addon_dev_python/services/python/samples/docker/__init__.py +0 -0
  81. {wexample_wex_addon_dev_python-15.8.1 → wexample_wex_addon_dev_python-15.9.0}/src/wexample_wex_addon_dev_python/services/python/samples/docker/docker-compose.yml +0 -0
  82. {wexample_wex_addon_dev_python-15.8.1 → wexample_wex_addon_dev_python-15.9.0}/src/wexample_wex_addon_dev_python/services/python/samples/docker/entrypoint.sh +0 -0
  83. {wexample_wex_addon_dev_python-15.8.1 → wexample_wex_addon_dev_python-15.9.0}/src/wexample_wex_addon_dev_python/services/python/samples/docker/images/Dockerfile.base +0 -0
  84. {wexample_wex_addon_dev_python-15.8.1 → wexample_wex_addon_dev_python-15.9.0}/src/wexample_wex_addon_dev_python/services/python/samples/docker/images/Dockerfile.develop +0 -0
  85. {wexample_wex_addon_dev_python-15.8.1 → wexample_wex_addon_dev_python-15.9.0}/src/wexample_wex_addon_dev_python/services/python/samples/docker/images/__init__.py +0 -0
  86. {wexample_wex_addon_dev_python-15.8.1 → wexample_wex_addon_dev_python-15.9.0}/src/wexample_wex_addon_dev_python/services/python/service.yml +0 -0
  87. {wexample_wex_addon_dev_python-15.8.1 → wexample_wex_addon_dev_python-15.9.0}/src/wexample_wex_addon_dev_python/workdir/__init__.py +0 -0
  88. {wexample_wex_addon_dev_python-15.8.1 → wexample_wex_addon_dev_python-15.9.0}/src/wexample_wex_addon_dev_python/workdir/mixin/__init__.py +0 -0
  89. {wexample_wex_addon_dev_python-15.8.1 → wexample_wex_addon_dev_python-15.9.0}/src/wexample_wex_addon_dev_python/workdir/mixin/with_profiling_python_workdir_mixin.py +0 -0
  90. {wexample_wex_addon_dev_python-15.8.1 → wexample_wex_addon_dev_python-15.9.0}/src/wexample_wex_addon_dev_python/workdir/python_packages_suite_workdir.py +0 -0
  91. {wexample_wex_addon_dev_python-15.8.1 → wexample_wex_addon_dev_python-15.9.0}/src/wexample_wex_addon_dev_python/workdir/python_workdir.py +0 -0
  92. {wexample_wex_addon_dev_python-15.8.1 → wexample_wex_addon_dev_python-15.9.0}/tests/.gitkeep +0 -0
  93. {wexample_wex_addon_dev_python-15.8.1 → wexample_wex_addon_dev_python-15.9.0}/tests/helper/__init__.py +0 -0
  94. {wexample_wex_addon_dev_python-15.8.1 → wexample_wex_addon_dev_python-15.9.0}/tests/helper/test_pdm.py +0 -0
  95. {wexample_wex_addon_dev_python-15.8.1 → wexample_wex_addon_dev_python-15.9.0}/tests/integration/__init__.py +0 -0
  96. {wexample_wex_addon_dev_python-15.8.1 → wexample_wex_addon_dev_python-15.9.0}/tests/integration/refactor/__init__.py +0 -0
  97. {wexample_wex_addon_dev_python-15.8.1 → wexample_wex_addon_dev_python-15.9.0}/tests/integration/refactor/test_python_class_rename_handler.py +0 -0
  98. {wexample_wex_addon_dev_python-15.8.1 → wexample_wex_addon_dev_python-15.9.0}/tests/integration/refactor/test_python_constant_rename_handler.py +0 -0
  99. {wexample_wex_addon_dev_python-15.8.1 → wexample_wex_addon_dev_python-15.9.0}/tests/integration/refactor/test_python_function_rename_handler.py +0 -0
  100. {wexample_wex_addon_dev_python-15.8.1 → wexample_wex_addon_dev_python-15.9.0}/tests/integration/refactor/test_python_module_rename_handler.py +0 -0
  101. {wexample_wex_addon_dev_python-15.8.1 → wexample_wex_addon_dev_python-15.9.0}/tests/integration/refactor/test_python_package_rename_handler.py +0 -0
  102. {wexample_wex_addon_dev_python-15.8.1 → wexample_wex_addon_dev_python-15.9.0}/tests/unit/__init__.py +0 -0
  103. {wexample_wex_addon_dev_python-15.8.1 → wexample_wex_addon_dev_python-15.9.0}/tests/unit/helper/__init__.py +0 -0
  104. {wexample_wex_addon_dev_python-15.8.1 → wexample_wex_addon_dev_python-15.9.0}/tests/unit/helper/test_pdm.py +0 -0
  105. {wexample_wex_addon_dev_python-15.8.1 → wexample_wex_addon_dev_python-15.9.0}/tests/unit/refactor/__init__.py +0 -0
  106. {wexample_wex_addon_dev_python-15.8.1 → wexample_wex_addon_dev_python-15.9.0}/tests/unit/refactor/test_abstract_python_path_rename_handler.py +0 -0
  107. {wexample_wex_addon_dev_python-15.8.1 → wexample_wex_addon_dev_python-15.9.0}/tests/unit/refactor/test_abstract_python_rename_handler.py +0 -0
  108. {wexample_wex_addon_dev_python-15.8.1 → wexample_wex_addon_dev_python-15.9.0}/tests/unit/refactor/test_abstract_python_symbol_rename_handler.py +0 -0
  109. {wexample_wex_addon_dev_python-15.8.1 → wexample_wex_addon_dev_python-15.9.0}/tests/unit/refactor/test_applier.py +0 -0
  110. {wexample_wex_addon_dev_python-15.8.1 → wexample_wex_addon_dev_python-15.9.0}/tests/unit/refactor/test_python_class_rename_handler.py +0 -0
  111. {wexample_wex_addon_dev_python-15.8.1 → wexample_wex_addon_dev_python-15.9.0}/tests/unit/refactor/test_python_common.py +0 -0
  112. {wexample_wex_addon_dev_python-15.8.1 → wexample_wex_addon_dev_python-15.9.0}/tests/unit/refactor/test_python_constant_rename_handler.py +0 -0
  113. {wexample_wex_addon_dev_python-15.8.1 → wexample_wex_addon_dev_python-15.9.0}/tests/unit/refactor/test_python_function_rename_handler.py +0 -0
  114. {wexample_wex_addon_dev_python-15.8.1 → wexample_wex_addon_dev_python-15.9.0}/tests/unit/refactor/test_python_module_rename_handler.py +0 -0
  115. {wexample_wex_addon_dev_python-15.8.1 → wexample_wex_addon_dev_python-15.9.0}/tests/unit/refactor/test_python_package_rename_handler.py +0 -0
  116. {wexample_wex_addon_dev_python-15.8.1 → wexample_wex_addon_dev_python-15.9.0}/tests/unit/refactor/test_rename_plan.py +0 -0
  117. {wexample_wex_addon_dev_python-15.8.1 → wexample_wex_addon_dev_python-15.9.0}/tests/unit/refactor/test_symbol_kind.py +0 -0
  118. {wexample_wex_addon_dev_python-15.8.1 → wexample_wex_addon_dev_python-15.9.0}/tests/unit/resources/__init__.py +0 -0
  119. {wexample_wex_addon_dev_python-15.8.1 → wexample_wex_addon_dev_python-15.9.0}/tests/unit/resources/test_shipped_agents.py +0 -0
  120. {wexample_wex_addon_dev_python-15.8.1 → wexample_wex_addon_dev_python-15.9.0}/tests/unit/workdir/__init__.py +0 -0
  121. {wexample_wex_addon_dev_python-15.8.1 → wexample_wex_addon_dev_python-15.9.0}/tests/unit/workdir/test_python_package_workdir.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: wexample-wex-addon-dev-python
3
- Version: 15.8.1
3
+ Version: 15.9.0
4
4
  Summary: Extends wex with commands to format, lint, and rename Python symbols, plus workdir types for Python packages and suites
5
5
  Author-Email: weeger <contact@wexample.com>
6
6
  License: MIT
@@ -20,7 +20,7 @@ Requires-Dist: pyright
20
20
  Requires-Dist: wexample-api>=6.8.0
21
21
  Requires-Dist: wexample-filestate-python>=9.4.0
22
22
  Requires-Dist: wexample-wex-addon-ai>=19.1.0
23
- Requires-Dist: wexample-wex-addon-app>=35.2.0
23
+ Requires-Dist: wexample-wex-addon-app>=35.3.0
24
24
  Provides-Extra: dev
25
25
  Requires-Dist: pytest; extra == "dev"
26
26
  Requires-Dist: pytest-cov; extra == "dev"
@@ -28,7 +28,7 @@ Description-Content-Type: text/markdown
28
28
 
29
29
  # wex_addon_dev_python
30
30
 
31
- Version: 15.8.1
31
+ Version: 15.9.0
32
32
 
33
33
  Extends wex with commands to format, lint, and rename Python symbols, plus workdir types for Python packages and suites
34
34
 
@@ -1,6 +1,6 @@
1
1
  # wex_addon_dev_python
2
2
 
3
- Version: 15.8.1
3
+ Version: 15.9.0
4
4
 
5
5
  Extends wex with commands to format, lint, and rename Python symbols, plus workdir types for Python packages and suites
6
6
 
@@ -6,7 +6,7 @@ build-backend = "pdm.backend"
6
6
 
7
7
  [project]
8
8
  name = "wexample-wex-addon-dev-python"
9
- version = "15.8.1"
9
+ version = "15.9.0"
10
10
  description = "Extends wex with commands to format, lint, and rename Python symbols, plus workdir types for Python packages and suites"
11
11
  authors = [
12
12
  { name = "weeger", email = "contact@wexample.com" },
@@ -29,7 +29,7 @@ dependencies = [
29
29
  "wexample-api>=6.8.0",
30
30
  "wexample-filestate-python>=9.4.0",
31
31
  "wexample-wex-addon-ai>=19.1.0",
32
- "wexample-wex-addon-app>=35.2.0",
32
+ "wexample-wex-addon-app>=35.3.0",
33
33
  ]
34
34
 
35
35
  [project.readme]
@@ -494,7 +494,10 @@ class PythonPackageWorkdir(PythonWorkdir):
494
494
  if self.get_gitlab_registry_url():
495
495
  self._publish_to_gitlab_registry(force=force)
496
496
  try:
497
- self._publish_to_pypi(force=force)
497
+ # In the background: PyPI only mirrors the GitLab registry,
498
+ # nothing waits for it. The suite's publication collects
499
+ # the uploads at its end (`collect_pypi_upload`).
500
+ self._publish_to_pypi(force=force, background=True)
498
501
  except ShellCommandFailedException as exception:
499
502
  self.warning(
500
503
  f"PyPI refused {package_name} {version}, published on the GitLab "
@@ -560,7 +563,34 @@ class PythonPackageWorkdir(PythonWorkdir):
560
563
  cwd=self.get_path(),
561
564
  )
562
565
 
563
- def _publish_to_pypi(self, force: bool = False) -> None:
566
+ def collect_pypi_upload(self) -> str | None:
567
+ """Wait for this package's background PyPI upload, if one is running,
568
+ and say what went wrong when it failed (None when it did not)."""
569
+ import os
570
+ import shutil
571
+ import time
572
+
573
+ upload_dir = self._get_pypi_upload_dir()
574
+ pid_file = upload_dir / "pid"
575
+ if not pid_file.is_file():
576
+ return None
577
+ pid = int(pid_file.read_text().strip() or 0)
578
+ while pid and os.path.exists(f"/proc/{pid}"):
579
+ time.sleep(1)
580
+ rc_file = upload_dir / "rc"
581
+ rc = rc_file.read_text().strip() if rc_file.is_file() else "unknown"
582
+ log_file = upload_dir / "log"
583
+ report = None
584
+ if rc != "0":
585
+ tail = log_file.read_text(errors="replace").splitlines()[-5:] if log_file.is_file() else []
586
+ report = f"{self.get_package_name()}: PyPI upload failed (exit {rc}): " + " / ".join(tail)
587
+ shutil.rmtree(upload_dir, ignore_errors=True)
588
+ return report
589
+
590
+ def _get_pypi_upload_dir(self):
591
+ return self.get_path() / ".wex" / "tmp" / "pypi-upload"
592
+
593
+ def _publish_to_pypi(self, force: bool = False, background: bool = False) -> None:
564
594
  from wexample_filestate_python.common.pipy_gateway import PipyGateway
565
595
  from wexample_helpers.helper.shell import shell_run
566
596
 
@@ -596,7 +626,30 @@ class PythonPackageWorkdir(PythonWorkdir):
596
626
  if password:
597
627
  publish_cmd += ["--password", password]
598
628
 
599
- shell_run(publish_cmd, inherit_stdio=True, cwd=self.get_path())
629
+ if not background:
630
+ shell_run(publish_cmd, inherit_stdio=True, cwd=self.get_path())
631
+ return
632
+
633
+ import shlex
634
+ import shutil
635
+ import subprocess
636
+
637
+ # From a copy of the distributions: dist/ is cleaned as soon as this
638
+ # returns. The exit code is written where collect_pypi_upload reads it.
639
+ upload_dir = self._get_pypi_upload_dir()
640
+ shutil.rmtree(upload_dir, ignore_errors=True)
641
+ shutil.copytree(self.get_path() / "dist", upload_dir / "dist")
642
+ command = " ".join(shlex.quote(part) for part in [*publish_cmd, "--dest", str(upload_dir / "dist")])
643
+ with open(upload_dir / "log", "w") as log:
644
+ process = subprocess.Popen(
645
+ ["sh", "-c", f'( {command} ); echo $? > "{upload_dir / "rc"}"'],
646
+ cwd=self.get_path(),
647
+ stdout=log,
648
+ stderr=subprocess.STDOUT,
649
+ start_new_session=True,
650
+ )
651
+ (upload_dir / "pid").write_text(str(process.pid))
652
+ self.log(f"PyPI upload of {package_name} {version} running in the background.")
600
653
 
601
654
  def _wait_for_registry(self) -> None:
602
655
  from wexample_helpers.helper.polling_callback_manager import (
@@ -0,0 +1,47 @@
1
+ from __future__ import annotations
2
+
3
+ import subprocess
4
+ from types import SimpleNamespace
5
+
6
+ from wexample_wex_addon_dev_python.workdir.python_package_workdir import (
7
+ PythonPackageWorkdir,
8
+ )
9
+
10
+
11
+ def _package(tmp_path):
12
+ """Just what collect_pypi_upload reads off a package."""
13
+ package = SimpleNamespace(get_path=lambda: tmp_path, get_package_name=lambda: "demo")
14
+ package._get_pypi_upload_dir = lambda: PythonPackageWorkdir._get_pypi_upload_dir(package)
15
+ return package
16
+
17
+
18
+ def _upload(tmp_path, script: str) -> None:
19
+ """A background upload as _publish_to_pypi leaves it: its pid, its log,
20
+ its exit code written when it ends."""
21
+ upload_dir = tmp_path / ".wex" / "tmp" / "pypi-upload"
22
+ upload_dir.mkdir(parents=True)
23
+ with open(upload_dir / "log", "w") as log:
24
+ process = subprocess.Popen(
25
+ ["sh", "-c", f'( {script} ); echo $? > "{upload_dir / "rc"}"'],
26
+ stdout=log,
27
+ stderr=subprocess.STDOUT,
28
+ )
29
+ (upload_dir / "pid").write_text(str(process.pid))
30
+ process.wait()
31
+
32
+
33
+ def test_nothing_to_collect_without_an_upload(tmp_path) -> None:
34
+ assert PythonPackageWorkdir.collect_pypi_upload(_package(tmp_path)) is None
35
+
36
+
37
+ def test_a_successful_upload_is_collected_silently(tmp_path) -> None:
38
+ _upload(tmp_path, "echo uploaded")
39
+ assert PythonPackageWorkdir.collect_pypi_upload(_package(tmp_path)) is None
40
+ assert not (tmp_path / ".wex" / "tmp" / "pypi-upload").exists()
41
+
42
+
43
+ def test_a_refused_upload_is_reported_with_its_log(tmp_path) -> None:
44
+ _upload(tmp_path, "echo 'HTTP 400 File already exists'; exit 1")
45
+ report = PythonPackageWorkdir.collect_pypi_upload(_package(tmp_path))
46
+ assert report.startswith("demo: PyPI upload failed (exit 1)")
47
+ assert "File already exists" in report