django-import-export 4.4.2__tar.gz → 4.4.4__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 (284) hide show
  1. {django_import_export-4.4.2 → django_import_export-4.4.4}/PKG-INFO +1 -1
  2. {django_import_export-4.4.2 → django_import_export-4.4.4}/django_import_export.egg-info/PKG-INFO +1 -1
  3. django_import_export-4.4.4/django_import_export.egg-info/scm_version.json +8 -0
  4. {django_import_export-4.4.2 → django_import_export-4.4.4}/docs/changelog.rst +15 -0
  5. {django_import_export-4.4.2 → django_import_export-4.4.4}/docs/release_notes.rst +47 -0
  6. {django_import_export-4.4.2 → django_import_export-4.4.4}/import_export/_version.py +3 -3
  7. {django_import_export-4.4.2 → django_import_export-4.4.4}/import_export/admin.py +15 -11
  8. {django_import_export-4.4.2 → django_import_export-4.4.4}/import_export/formats/base_formats.py +14 -0
  9. {django_import_export-4.4.2 → django_import_export-4.4.4}/import_export/results.py +1 -1
  10. {django_import_export-4.4.2 → django_import_export-4.4.4}/import_export/widgets.py +15 -2
  11. {django_import_export-4.4.2 → django_import_export-4.4.4}/tests/core/tests/admin_integration/test_action_export.py +60 -2
  12. {django_import_export-4.4.2 → django_import_export-4.4.4}/tests/core/tests/test_base_formats.py +8 -0
  13. {django_import_export-4.4.2 → django_import_export-4.4.4}/tests/core/tests/test_widgets.py +24 -0
  14. django_import_export-4.4.2/django_import_export.egg-info/scm_version.json +0 -8
  15. {django_import_export-4.4.2 → django_import_export-4.4.4}/.coveragerc +0 -0
  16. {django_import_export-4.4.2 → django_import_export-4.4.4}/.editorconfig +0 -0
  17. {django_import_export-4.4.2 → django_import_export-4.4.4}/.flake8 +0 -0
  18. {django_import_export-4.4.2 → django_import_export-4.4.4}/.git-blame-ignore-revs +0 -0
  19. {django_import_export-4.4.2 → django_import_export-4.4.4}/.github/FUNDING.yml +0 -0
  20. {django_import_export-4.4.2 → django_import_export-4.4.4}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
  21. {django_import_export-4.4.2 → django_import_export-4.4.4}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
  22. {django_import_export-4.4.2 → django_import_export-4.4.4}/.github/ISSUE_TEMPLATE/question.md +0 -0
  23. {django_import_export-4.4.2 → django_import_export-4.4.4}/.github/pull_request_template.md +0 -0
  24. {django_import_export-4.4.2 → django_import_export-4.4.4}/.github/stale.yml +0 -0
  25. {django_import_export-4.4.2 → django_import_export-4.4.4}/.github/workflows/release.yml +0 -0
  26. {django_import_export-4.4.2 → django_import_export-4.4.4}/.github/workflows/test.yml +0 -0
  27. {django_import_export-4.4.2 → django_import_export-4.4.4}/.gitignore +0 -0
  28. {django_import_export-4.4.2 → django_import_export-4.4.4}/.pre-commit-config.yaml +0 -0
  29. {django_import_export-4.4.2 → django_import_export-4.4.4}/.readthedocs.yaml +0 -0
  30. {django_import_export-4.4.2 → django_import_export-4.4.4}/AUTHORS +0 -0
  31. {django_import_export-4.4.2 → django_import_export-4.4.4}/CODE_OF_CONDUCT.md +0 -0
  32. {django_import_export-4.4.2 → django_import_export-4.4.4}/CONTRIBUTING.md +0 -0
  33. {django_import_export-4.4.2 → django_import_export-4.4.4}/LICENSE +0 -0
  34. {django_import_export-4.4.2 → django_import_export-4.4.4}/Makefile +0 -0
  35. {django_import_export-4.4.2 → django_import_export-4.4.4}/README.rst +0 -0
  36. {django_import_export-4.4.2 → django_import_export-4.4.4}/RELEASE.md +0 -0
  37. {django_import_export-4.4.2 → django_import_export-4.4.4}/SECURITY.md +0 -0
  38. {django_import_export-4.4.2 → django_import_export-4.4.4}/django_import_export.egg-info/SOURCES.txt +0 -0
  39. {django_import_export-4.4.2 → django_import_export-4.4.4}/django_import_export.egg-info/dependency_links.txt +0 -0
  40. {django_import_export-4.4.2 → django_import_export-4.4.4}/django_import_export.egg-info/requires.txt +0 -0
  41. {django_import_export-4.4.2 → django_import_export-4.4.4}/django_import_export.egg-info/scm_file_list.json +0 -0
  42. {django_import_export-4.4.2 → django_import_export-4.4.4}/django_import_export.egg-info/top_level.txt +0 -0
  43. {django_import_export-4.4.2 → django_import_export-4.4.4}/docs/Makefile +0 -0
  44. {django_import_export-4.4.2 → django_import_export-4.4.4}/docs/_static/images/change-form-export.png +0 -0
  45. {django_import_export-4.4.2 → django_import_export-4.4.4}/docs/_static/images/custom-export-form.png +0 -0
  46. {django_import_export-4.4.2 → django_import_export-4.4.4}/docs/_static/images/custom-import-form.png +0 -0
  47. {django_import_export-4.4.2 → django_import_export-4.4.4}/docs/_static/images/date-widget-validation-error.png +0 -0
  48. {django_import_export-4.4.2 → django_import_export-4.4.4}/docs/_static/images/django-import-export-change.png +0 -0
  49. {django_import_export-4.4.2 → django_import_export-4.4.4}/docs/_static/images/django-import-export-export-confirm.png +0 -0
  50. {django_import_export-4.4.2 → django_import_export-4.4.4}/docs/_static/images/django-import-export-import-confirm.png +0 -0
  51. {django_import_export-4.4.2 → django_import_export-4.4.4}/docs/_static/images/django-import-export-import.png +0 -0
  52. {django_import_export-4.4.2 → django_import_export-4.4.4}/docs/_static/images/export-button.png +0 -0
  53. {django_import_export-4.4.2 → django_import_export-4.4.4}/docs/_static/images/export_workflow.svg +0 -0
  54. {django_import_export-4.4.2 → django_import_export-4.4.4}/docs/_static/images/import-button.png +0 -0
  55. {django_import_export-4.4.2 → django_import_export-4.4.4}/docs/_static/images/import_workflow.svg +0 -0
  56. {django_import_export-4.4.2 → django_import_export-4.4.4}/docs/_static/images/non-field-specific-validation-error.png +0 -0
  57. {django_import_export-4.4.2 → django_import_export-4.4.4}/docs/_static/images/screenshots/confirm-import.png +0 -0
  58. {django_import_export-4.4.2 → django_import_export-4.4.4}/docs/_static/images/screenshots/export-form.png +0 -0
  59. {django_import_export-4.4.2 → django_import_export-4.4.4}/docs/_static/images/screenshots/export-selected-action.png +0 -0
  60. {django_import_export-4.4.2 → django_import_export-4.4.4}/docs/_static/images/screenshots/import-complete.png +0 -0
  61. {django_import_export-4.4.2 → django_import_export-4.4.4}/docs/_static/images/screenshots/import-form.png +0 -0
  62. {django_import_export-4.4.2 → django_import_export-4.4.4}/docs/_static/images/screenshots/import-update-with-authors.png +0 -0
  63. {django_import_export-4.4.2 → django_import_export-4.4.4}/docs/_static/images/select-for-export.png +0 -0
  64. {django_import_export-4.4.2 → django_import_export-4.4.4}/docs/admin_integration.rst +0 -0
  65. {django_import_export-4.4.2 → django_import_export-4.4.4}/docs/advanced_usage.rst +0 -0
  66. {django_import_export-4.4.2 → django_import_export-4.4.4}/docs/api_admin.rst +0 -0
  67. {django_import_export-4.4.2 → django_import_export-4.4.4}/docs/api_exceptions.rst +0 -0
  68. {django_import_export-4.4.2 → django_import_export-4.4.4}/docs/api_fields.rst +0 -0
  69. {django_import_export-4.4.2 → django_import_export-4.4.4}/docs/api_forms.rst +0 -0
  70. {django_import_export-4.4.2 → django_import_export-4.4.4}/docs/api_instance_loaders.rst +0 -0
  71. {django_import_export-4.4.2 → django_import_export-4.4.4}/docs/api_mixins.rst +0 -0
  72. {django_import_export-4.4.2 → django_import_export-4.4.4}/docs/api_resources.rst +0 -0
  73. {django_import_export-4.4.2 → django_import_export-4.4.4}/docs/api_results.rst +0 -0
  74. {django_import_export-4.4.2 → django_import_export-4.4.4}/docs/api_tmp_storages.rst +0 -0
  75. {django_import_export-4.4.2 → django_import_export-4.4.4}/docs/api_widgets.rst +0 -0
  76. {django_import_export-4.4.2 → django_import_export-4.4.4}/docs/bulk_import.rst +0 -0
  77. {django_import_export-4.4.2 → django_import_export-4.4.4}/docs/celery.rst +0 -0
  78. {django_import_export-4.4.2 → django_import_export-4.4.4}/docs/conf.py +0 -0
  79. {django_import_export-4.4.2 → django_import_export-4.4.4}/docs/contributing.rst +0 -0
  80. {django_import_export-4.4.2 → django_import_export-4.4.4}/docs/export_workflow.rst +0 -0
  81. {django_import_export-4.4.2 → django_import_export-4.4.4}/docs/faq.rst +0 -0
  82. {django_import_export-4.4.2 → django_import_export-4.4.4}/docs/getting_started.rst +0 -0
  83. {django_import_export-4.4.2 → django_import_export-4.4.4}/docs/image_src/export_workflow.txt +0 -0
  84. {django_import_export-4.4.2 → django_import_export-4.4.4}/docs/image_src/import_workflow.txt +0 -0
  85. {django_import_export-4.4.2 → django_import_export-4.4.4}/docs/import_workflow.rst +0 -0
  86. {django_import_export-4.4.2 → django_import_export-4.4.4}/docs/index.rst +0 -0
  87. {django_import_export-4.4.2 → django_import_export-4.4.4}/docs/installation.rst +0 -0
  88. {django_import_export-4.4.2 → django_import_export-4.4.4}/docs/make.bat +0 -0
  89. {django_import_export-4.4.2 → django_import_export-4.4.4}/docs/management_commands.rst +0 -0
  90. {django_import_export-4.4.2 → django_import_export-4.4.4}/docs/screenshots.rst +0 -0
  91. {django_import_export-4.4.2 → django_import_export-4.4.4}/docs/testing.rst +0 -0
  92. {django_import_export-4.4.2 → django_import_export-4.4.4}/import_export/__init__.py +0 -0
  93. {django_import_export-4.4.2 → django_import_export-4.4.4}/import_export/command_utils.py +0 -0
  94. {django_import_export-4.4.2 → django_import_export-4.4.4}/import_export/declarative.py +0 -0
  95. {django_import_export-4.4.2 → django_import_export-4.4.4}/import_export/exceptions.py +0 -0
  96. {django_import_export-4.4.2 → django_import_export-4.4.4}/import_export/fields.py +0 -0
  97. {django_import_export-4.4.2 → django_import_export-4.4.4}/import_export/formats/__init__.py +0 -0
  98. {django_import_export-4.4.2 → django_import_export-4.4.4}/import_export/forms.py +0 -0
  99. {django_import_export-4.4.2 → django_import_export-4.4.4}/import_export/instance_loaders.py +0 -0
  100. {django_import_export-4.4.2 → django_import_export-4.4.4}/import_export/locale/ar/LC_MESSAGES/django.mo +0 -0
  101. {django_import_export-4.4.2 → django_import_export-4.4.4}/import_export/locale/ar/LC_MESSAGES/django.po +0 -0
  102. {django_import_export-4.4.2 → django_import_export-4.4.4}/import_export/locale/bg/LC_MESSAGES/django.mo +0 -0
  103. {django_import_export-4.4.2 → django_import_export-4.4.4}/import_export/locale/bg/LC_MESSAGES/django.po +0 -0
  104. {django_import_export-4.4.2 → django_import_export-4.4.4}/import_export/locale/ca/LC_MESSAGES/django.mo +0 -0
  105. {django_import_export-4.4.2 → django_import_export-4.4.4}/import_export/locale/ca/LC_MESSAGES/django.po +0 -0
  106. {django_import_export-4.4.2 → django_import_export-4.4.4}/import_export/locale/cs/LC_MESSAGES/django.mo +0 -0
  107. {django_import_export-4.4.2 → django_import_export-4.4.4}/import_export/locale/cs/LC_MESSAGES/django.po +0 -0
  108. {django_import_export-4.4.2 → django_import_export-4.4.4}/import_export/locale/de/LC_MESSAGES/django.mo +0 -0
  109. {django_import_export-4.4.2 → django_import_export-4.4.4}/import_export/locale/de/LC_MESSAGES/django.po +0 -0
  110. {django_import_export-4.4.2 → django_import_export-4.4.4}/import_export/locale/es/LC_MESSAGES/django.mo +0 -0
  111. {django_import_export-4.4.2 → django_import_export-4.4.4}/import_export/locale/es/LC_MESSAGES/django.po +0 -0
  112. {django_import_export-4.4.2 → django_import_export-4.4.4}/import_export/locale/es_AR/LC_MESSAGES/django.mo +0 -0
  113. {django_import_export-4.4.2 → django_import_export-4.4.4}/import_export/locale/es_AR/LC_MESSAGES/django.po +0 -0
  114. {django_import_export-4.4.2 → django_import_export-4.4.4}/import_export/locale/fa/LC_MESSAGES/django.mo +0 -0
  115. {django_import_export-4.4.2 → django_import_export-4.4.4}/import_export/locale/fa/LC_MESSAGES/django.po +0 -0
  116. {django_import_export-4.4.2 → django_import_export-4.4.4}/import_export/locale/fi/LC_MESSAGES/django.mo +0 -0
  117. {django_import_export-4.4.2 → django_import_export-4.4.4}/import_export/locale/fi/LC_MESSAGES/django.po +0 -0
  118. {django_import_export-4.4.2 → django_import_export-4.4.4}/import_export/locale/fr/LC_MESSAGES/django.mo +0 -0
  119. {django_import_export-4.4.2 → django_import_export-4.4.4}/import_export/locale/fr/LC_MESSAGES/django.po +0 -0
  120. {django_import_export-4.4.2 → django_import_export-4.4.4}/import_export/locale/he/LC_MESSAGES/django.mo +0 -0
  121. {django_import_export-4.4.2 → django_import_export-4.4.4}/import_export/locale/he/LC_MESSAGES/django.po +0 -0
  122. {django_import_export-4.4.2 → django_import_export-4.4.4}/import_export/locale/it/LC_MESSAGES/django.mo +0 -0
  123. {django_import_export-4.4.2 → django_import_export-4.4.4}/import_export/locale/it/LC_MESSAGES/django.po +0 -0
  124. {django_import_export-4.4.2 → django_import_export-4.4.4}/import_export/locale/ja/LC_MESSAGES/django.mo +0 -0
  125. {django_import_export-4.4.2 → django_import_export-4.4.4}/import_export/locale/ja/LC_MESSAGES/django.po +0 -0
  126. {django_import_export-4.4.2 → django_import_export-4.4.4}/import_export/locale/ko/LC_MESSAGES/django.mo +0 -0
  127. {django_import_export-4.4.2 → django_import_export-4.4.4}/import_export/locale/ko/LC_MESSAGES/django.po +0 -0
  128. {django_import_export-4.4.2 → django_import_export-4.4.4}/import_export/locale/kz/LC_MESSAGES/django.mo +0 -0
  129. {django_import_export-4.4.2 → django_import_export-4.4.4}/import_export/locale/kz/LC_MESSAGES/django.po +0 -0
  130. {django_import_export-4.4.2 → django_import_export-4.4.4}/import_export/locale/nl/LC_MESSAGES/django.mo +0 -0
  131. {django_import_export-4.4.2 → django_import_export-4.4.4}/import_export/locale/nl/LC_MESSAGES/django.po +0 -0
  132. {django_import_export-4.4.2 → django_import_export-4.4.4}/import_export/locale/pl/LC_MESSAGES/django.mo +0 -0
  133. {django_import_export-4.4.2 → django_import_export-4.4.4}/import_export/locale/pl/LC_MESSAGES/django.po +0 -0
  134. {django_import_export-4.4.2 → django_import_export-4.4.4}/import_export/locale/pt_BR/LC_MESSAGES/django.mo +0 -0
  135. {django_import_export-4.4.2 → django_import_export-4.4.4}/import_export/locale/pt_BR/LC_MESSAGES/django.po +0 -0
  136. {django_import_export-4.4.2 → django_import_export-4.4.4}/import_export/locale/ru/LC_MESSAGES/django.mo +0 -0
  137. {django_import_export-4.4.2 → django_import_export-4.4.4}/import_export/locale/ru/LC_MESSAGES/django.po +0 -0
  138. {django_import_export-4.4.2 → django_import_export-4.4.4}/import_export/locale/sk/LC_MESSAGES/django.mo +0 -0
  139. {django_import_export-4.4.2 → django_import_export-4.4.4}/import_export/locale/sk/LC_MESSAGES/django.po +0 -0
  140. {django_import_export-4.4.2 → django_import_export-4.4.4}/import_export/locale/tr/LC_MESSAGES/django.mo +0 -0
  141. {django_import_export-4.4.2 → django_import_export-4.4.4}/import_export/locale/tr/LC_MESSAGES/django.po +0 -0
  142. {django_import_export-4.4.2 → django_import_export-4.4.4}/import_export/locale/uk/LC_MESSAGES/django.mo +0 -0
  143. {django_import_export-4.4.2 → django_import_export-4.4.4}/import_export/locale/uk/LC_MESSAGES/django.po +0 -0
  144. {django_import_export-4.4.2 → django_import_export-4.4.4}/import_export/locale/zh_Hans/LC_MESSAGES/django.mo +0 -0
  145. {django_import_export-4.4.2 → django_import_export-4.4.4}/import_export/locale/zh_Hans/LC_MESSAGES/django.po +0 -0
  146. {django_import_export-4.4.2 → django_import_export-4.4.4}/import_export/management/__init__.py +0 -0
  147. {django_import_export-4.4.2 → django_import_export-4.4.4}/import_export/management/commands/__init__.py +0 -0
  148. {django_import_export-4.4.2 → django_import_export-4.4.4}/import_export/management/commands/export.py +0 -0
  149. {django_import_export-4.4.2 → django_import_export-4.4.4}/import_export/management/commands/import.py +0 -0
  150. {django_import_export-4.4.2 → django_import_export-4.4.4}/import_export/mixins.py +0 -0
  151. {django_import_export-4.4.2 → django_import_export-4.4.4}/import_export/options.py +0 -0
  152. {django_import_export-4.4.2 → django_import_export-4.4.4}/import_export/resources.py +0 -0
  153. {django_import_export-4.4.2 → django_import_export-4.4.4}/import_export/signals.py +0 -0
  154. {django_import_export-4.4.2 → django_import_export-4.4.4}/import_export/static/import_export/export.css +0 -0
  155. {django_import_export-4.4.2 → django_import_export-4.4.4}/import_export/static/import_export/export_selectable_fields.js +0 -0
  156. {django_import_export-4.4.2 → django_import_export-4.4.4}/import_export/static/import_export/guess_format.js +0 -0
  157. {django_import_export-4.4.2 → django_import_export-4.4.4}/import_export/static/import_export/import.css +0 -0
  158. {django_import_export-4.4.2 → django_import_export-4.4.4}/import_export/templates/admin/import_export/base.html +0 -0
  159. {django_import_export-4.4.2 → django_import_export-4.4.4}/import_export/templates/admin/import_export/change_form.html +0 -0
  160. {django_import_export-4.4.2 → django_import_export-4.4.4}/import_export/templates/admin/import_export/change_list.html +0 -0
  161. {django_import_export-4.4.2 → django_import_export-4.4.4}/import_export/templates/admin/import_export/change_list_export.html +0 -0
  162. {django_import_export-4.4.2 → django_import_export-4.4.4}/import_export/templates/admin/import_export/change_list_export_item.html +0 -0
  163. {django_import_export-4.4.2 → django_import_export-4.4.4}/import_export/templates/admin/import_export/change_list_import.html +0 -0
  164. {django_import_export-4.4.2 → django_import_export-4.4.4}/import_export/templates/admin/import_export/change_list_import_export.html +0 -0
  165. {django_import_export-4.4.2 → django_import_export-4.4.4}/import_export/templates/admin/import_export/change_list_import_item.html +0 -0
  166. {django_import_export-4.4.2 → django_import_export-4.4.4}/import_export/templates/admin/import_export/export.html +0 -0
  167. {django_import_export-4.4.2 → django_import_export-4.4.4}/import_export/templates/admin/import_export/import.html +0 -0
  168. {django_import_export-4.4.2 → django_import_export-4.4.4}/import_export/templates/admin/import_export/resource_fields_list.html +0 -0
  169. {django_import_export-4.4.2 → django_import_export-4.4.4}/import_export/templatetags/__init__.py +0 -0
  170. {django_import_export-4.4.2 → django_import_export-4.4.4}/import_export/templatetags/import_export_tags.py +0 -0
  171. {django_import_export-4.4.2 → django_import_export-4.4.4}/import_export/tmp_storages.py +0 -0
  172. {django_import_export-4.4.2 → django_import_export-4.4.4}/import_export/utils.py +0 -0
  173. {django_import_export-4.4.2 → django_import_export-4.4.4}/pyproject.toml +0 -0
  174. {django_import_export-4.4.2 → django_import_export-4.4.4}/runtests.sh +0 -0
  175. {django_import_export-4.4.2 → django_import_export-4.4.4}/setup.cfg +0 -0
  176. {django_import_export-4.4.2 → django_import_export-4.4.4}/tests/books-sample.csv +0 -0
  177. {django_import_export-4.4.2 → django_import_export-4.4.4}/tests/core/__init__.py +0 -0
  178. {django_import_export-4.4.2 → django_import_export-4.4.4}/tests/core/admin.py +0 -0
  179. {django_import_export-4.4.2 → django_import_export-4.4.4}/tests/core/exports/authors.csv +0 -0
  180. {django_import_export-4.4.2 → django_import_export-4.4.4}/tests/core/exports/books-ISO-8859-1.csv +0 -0
  181. {django_import_export-4.4.2 → django_import_export-4.4.4}/tests/core/exports/books-dos.csv +0 -0
  182. {django_import_export-4.4.2 → django_import_export-4.4.4}/tests/core/exports/books-empty-author-email.xlsx +0 -0
  183. {django_import_export-4.4.2 → django_import_export-4.4.4}/tests/core/exports/books-for-delete.csv +0 -0
  184. {django_import_export-4.4.2 → django_import_export-4.4.4}/tests/core/exports/books-invalid-date.csv +0 -0
  185. {django_import_export-4.4.2 → django_import_export-4.4.4}/tests/core/exports/books-mac.csv +0 -0
  186. {django_import_export-4.4.2 → django_import_export-4.4.4}/tests/core/exports/books-mac.tsv +0 -0
  187. {django_import_export-4.4.2 → django_import_export-4.4.4}/tests/core/exports/books-no-headers.csv +0 -0
  188. {django_import_export-4.4.2 → django_import_export-4.4.4}/tests/core/exports/books-unicode.csv +0 -0
  189. {django_import_export-4.4.2 → django_import_export-4.4.4}/tests/core/exports/books-unicode.tsv +0 -0
  190. {django_import_export-4.4.2 → django_import_export-4.4.4}/tests/core/exports/books.csv +0 -0
  191. {django_import_export-4.4.2 → django_import_export-4.4.4}/tests/core/exports/books.json +0 -0
  192. {django_import_export-4.4.2 → django_import_export-4.4.4}/tests/core/exports/books.xls +0 -0
  193. {django_import_export-4.4.2 → django_import_export-4.4.4}/tests/core/exports/books.xlsx +0 -0
  194. {django_import_export-4.4.2 → django_import_export-4.4.4}/tests/core/exports/child.csv +0 -0
  195. {django_import_export-4.4.2 → django_import_export-4.4.4}/tests/core/exports/ebooks.csv +0 -0
  196. {django_import_export-4.4.2 → django_import_export-4.4.4}/tests/core/fixtures/author.json +0 -0
  197. {django_import_export-4.4.2 → django_import_export-4.4.4}/tests/core/fixtures/book.json +0 -0
  198. {django_import_export-4.4.2 → django_import_export-4.4.4}/tests/core/fixtures/category.json +0 -0
  199. {django_import_export-4.4.2 → django_import_export-4.4.4}/tests/core/forms.py +0 -0
  200. {django_import_export-4.4.2 → django_import_export-4.4.4}/tests/core/migrations/0001_initial.py +0 -0
  201. {django_import_export-4.4.2 → django_import_export-4.4.4}/tests/core/migrations/0002_book_published_time.py +0 -0
  202. {django_import_export-4.4.2 → django_import_export-4.4.4}/tests/core/migrations/0003_withfloatfield.py +0 -0
  203. {django_import_export-4.4.2 → django_import_export-4.4.4}/tests/core/migrations/0004_bookwithchapters.py +0 -0
  204. {django_import_export-4.4.2 → django_import_export-4.4.4}/tests/core/migrations/0005_addparentchild.py +0 -0
  205. {django_import_export-4.4.2 → django_import_export-4.4.4}/tests/core/migrations/0006_auto_20171130_0147.py +0 -0
  206. {django_import_export-4.4.2 → django_import_export-4.4.4}/tests/core/migrations/0007_auto_20180628_0411.py +0 -0
  207. {django_import_export-4.4.2 → django_import_export-4.4.4}/tests/core/migrations/0008_auto_20190409_0846.py +0 -0
  208. {django_import_export-4.4.2 → django_import_export-4.4.4}/tests/core/migrations/0009_auto_20211111_0807.py +0 -0
  209. {django_import_export-4.4.2 → django_import_export-4.4.4}/tests/core/migrations/0010_uuidbook.py +0 -0
  210. {django_import_export-4.4.2 → django_import_export-4.4.4}/tests/core/migrations/0011_uuidcategory_legacybook_alter_uuidbook_id_and_more.py +0 -0
  211. {django_import_export-4.4.2 → django_import_export-4.4.4}/tests/core/migrations/0012_delete_legacybook.py +0 -0
  212. {django_import_export-4.4.2 → django_import_export-4.4.4}/tests/core/migrations/0013_alter_author_birthday.py +0 -0
  213. {django_import_export-4.4.2 → django_import_export-4.4.4}/tests/core/migrations/0014_bookwithchapternumbers.py +0 -0
  214. {django_import_export-4.4.2 → django_import_export-4.4.4}/tests/core/migrations/0015_withpositiveintegerfields.py +0 -0
  215. {django_import_export-4.4.2 → django_import_export-4.4.4}/tests/core/migrations/0016_alter_category_options_alter_uuidcategory_options.py +0 -0
  216. {django_import_export-4.4.2 → django_import_export-4.4.4}/tests/core/migrations/0017_namedauthor_uuidbook_author.py +0 -0
  217. {django_import_export-4.4.2 → django_import_export-4.4.4}/tests/core/migrations/__init__.py +0 -0
  218. {django_import_export-4.4.2 → django_import_export-4.4.4}/tests/core/models.py +0 -0
  219. {django_import_export-4.4.2 → django_import_export-4.4.4}/tests/core/templates/core/admin/change_list.html +0 -0
  220. {django_import_export-4.4.2 → django_import_export-4.4.4}/tests/core/templates/core/category_list.html +0 -0
  221. {django_import_export-4.4.2 → django_import_export-4.4.4}/tests/core/tests/__init__.py +0 -0
  222. {django_import_export-4.4.2 → django_import_export-4.4.4}/tests/core/tests/admin_integration/__init__.py +0 -0
  223. {django_import_export-4.4.2 → django_import_export-4.4.4}/tests/core/tests/admin_integration/mixins.py +0 -0
  224. {django_import_export-4.4.2 → django_import_export-4.4.4}/tests/core/tests/admin_integration/test_export.py +0 -0
  225. {django_import_export-4.4.2 → django_import_export-4.4.4}/tests/core/tests/admin_integration/test_import_encoding.py +0 -0
  226. {django_import_export-4.4.2 → django_import_export-4.4.4}/tests/core/tests/admin_integration/test_import_errors.py +0 -0
  227. {django_import_export-4.4.2 → django_import_export-4.4.4}/tests/core/tests/admin_integration/test_import_functionality.py +0 -0
  228. {django_import_export-4.4.2 → django_import_export-4.4.4}/tests/core/tests/admin_integration/test_import_security.py +0 -0
  229. {django_import_export-4.4.2 → django_import_export-4.4.4}/tests/core/tests/admin_integration/test_import_templates.py +0 -0
  230. {django_import_export-4.4.2 → django_import_export-4.4.4}/tests/core/tests/admin_integration/test_views.py +0 -0
  231. {django_import_export-4.4.2 → django_import_export-4.4.4}/tests/core/tests/resources.py +0 -0
  232. {django_import_export-4.4.2 → django_import_export-4.4.4}/tests/core/tests/test_command_export.py +0 -0
  233. {django_import_export-4.4.2 → django_import_export-4.4.4}/tests/core/tests/test_command_import.py +0 -0
  234. {django_import_export-4.4.2 → django_import_export-4.4.4}/tests/core/tests/test_command_utils.py +0 -0
  235. {django_import_export-4.4.2 → django_import_export-4.4.4}/tests/core/tests/test_declarative.py +0 -0
  236. {django_import_export-4.4.2 → django_import_export-4.4.4}/tests/core/tests/test_fields.py +0 -0
  237. {django_import_export-4.4.2 → django_import_export-4.4.4}/tests/core/tests/test_forms.py +0 -0
  238. {django_import_export-4.4.2 → django_import_export-4.4.4}/tests/core/tests/test_import_export_tags.py +0 -0
  239. {django_import_export-4.4.2 → django_import_export-4.4.4}/tests/core/tests/test_instance_loaders.py +0 -0
  240. {django_import_export-4.4.2 → django_import_export-4.4.4}/tests/core/tests/test_invalidrow.py +0 -0
  241. {django_import_export-4.4.2 → django_import_export-4.4.4}/tests/core/tests/test_mixins.py +0 -0
  242. {django_import_export-4.4.2 → django_import_export-4.4.4}/tests/core/tests/test_model_resource_fields_generate_widgets.py +0 -0
  243. {django_import_export-4.4.2 → django_import_export-4.4.4}/tests/core/tests/test_permissions.py +0 -0
  244. {django_import_export-4.4.2 → django_import_export-4.4.4}/tests/core/tests/test_resources/__init__.py +0 -0
  245. {django_import_export-4.4.2 → django_import_export-4.4.4}/tests/core/tests/test_resources/test_bulk_operations.py +0 -0
  246. {django_import_export-4.4.2 → django_import_export-4.4.4}/tests/core/tests/test_resources/test_diffs.py +0 -0
  247. {django_import_export-4.4.2 → django_import_export-4.4.4}/tests/core/tests/test_resources/test_import_export.py +0 -0
  248. {django_import_export-4.4.2 → django_import_export-4.4.4}/tests/core/tests/test_resources/test_misc.py +0 -0
  249. {django_import_export-4.4.2 → django_import_export-4.4.4}/tests/core/tests/test_resources/test_modelresource/__init__.py +0 -0
  250. {django_import_export-4.4.2 → django_import_export-4.4.4}/tests/core/tests/test_resources/test_modelresource/test_data_deletion.py +0 -0
  251. {django_import_export-4.4.2 → django_import_export-4.4.4}/tests/core/tests/test_resources/test_modelresource/test_data_handling.py +0 -0
  252. {django_import_export-4.4.2 → django_import_export-4.4.4}/tests/core/tests/test_resources/test_modelresource/test_data_import.py +0 -0
  253. {django_import_export-4.4.2 → django_import_export-4.4.4}/tests/core/tests/test_resources/test_modelresource/test_deprecated_fields.py +0 -0
  254. {django_import_export-4.4.2 → django_import_export-4.4.4}/tests/core/tests/test_resources/test_modelresource/test_dynamic_customization.py +0 -0
  255. {django_import_export-4.4.2 → django_import_export-4.4.4}/tests/core/tests/test_resources/test_modelresource/test_error_handling.py +0 -0
  256. {django_import_export-4.4.2 → django_import_export-4.4.4}/tests/core/tests/test_resources/test_modelresource/test_export.py +0 -0
  257. {django_import_export-4.4.2 → django_import_export-4.4.4}/tests/core/tests/test_resources/test_modelresource/test_fields.py +0 -0
  258. {django_import_export-4.4.2 → django_import_export-4.4.4}/tests/core/tests/test_resources/test_modelresource/test_m2m.py +0 -0
  259. {django_import_export-4.4.2 → django_import_export-4.4.4}/tests/core/tests/test_resources/test_modelresource/test_queryset.py +0 -0
  260. {django_import_export-4.4.2 → django_import_export-4.4.4}/tests/core/tests/test_resources/test_modelresource/test_relationship.py +0 -0
  261. {django_import_export-4.4.2 → django_import_export-4.4.4}/tests/core/tests/test_resources/test_modelresource/test_resource.py +0 -0
  262. {django_import_export-4.4.2 → django_import_export-4.4.4}/tests/core/tests/test_resources/test_modelresource/test_resource_factory.py +0 -0
  263. {django_import_export-4.4.2 → django_import_export-4.4.4}/tests/core/tests/test_resources/test_modelresource/test_resource_fields.py +0 -0
  264. {django_import_export-4.4.2 → django_import_export-4.4.4}/tests/core/tests/test_resources/test_modelresource/test_resource_postgres.py +0 -0
  265. {django_import_export-4.4.2 → django_import_export-4.4.4}/tests/core/tests/test_resources/test_modelresource/test_resource_setup.py +0 -0
  266. {django_import_export-4.4.2 → django_import_export-4.4.4}/tests/core/tests/test_resources/test_modelresource/test_resource_transactions.py +0 -0
  267. {django_import_export-4.4.2 → django_import_export-4.4.4}/tests/core/tests/test_resources/test_modelresource/test_string_resource.py +0 -0
  268. {django_import_export-4.4.2 → django_import_export-4.4.4}/tests/core/tests/test_resources/test_modelresource/test_widget.py +0 -0
  269. {django_import_export-4.4.2 → django_import_export-4.4.4}/tests/core/tests/test_resources/test_natural_foreign_key.py +0 -0
  270. {django_import_export-4.4.2 → django_import_export-4.4.4}/tests/core/tests/test_resources/test_relationships.py +0 -0
  271. {django_import_export-4.4.2 → django_import_export-4.4.4}/tests/core/tests/test_results.py +0 -0
  272. {django_import_export-4.4.2 → django_import_export-4.4.4}/tests/core/tests/test_tmp_storages.py +0 -0
  273. {django_import_export-4.4.2 → django_import_export-4.4.4}/tests/core/tests/utils.py +0 -0
  274. {django_import_export-4.4.2 → django_import_export-4.4.4}/tests/core/tests/widget.py +0 -0
  275. {django_import_export-4.4.2 → django_import_export-4.4.4}/tests/core/views.py +0 -0
  276. {django_import_export-4.4.2 → django_import_export-4.4.4}/tests/docker/db/init-mysql-db.sh +0 -0
  277. {django_import_export-4.4.2 → django_import_export-4.4.4}/tests/docker/db/init-postgres-db.sh +0 -0
  278. {django_import_export-4.4.2 → django_import_export-4.4.4}/tests/docker-compose.yml +0 -0
  279. {django_import_export-4.4.2 → django_import_export-4.4.4}/tests/manage.py +0 -0
  280. {django_import_export-4.4.2 → django_import_export-4.4.4}/tests/scripts/__init__.py +0 -0
  281. {django_import_export-4.4.2 → django_import_export-4.4.4}/tests/scripts/bulk_import.py +0 -0
  282. {django_import_export-4.4.2 → django_import_export-4.4.4}/tests/settings.py +0 -0
  283. {django_import_export-4.4.2 → django_import_export-4.4.4}/tests/urls.py +0 -0
  284. {django_import_export-4.4.2 → django_import_export-4.4.4}/tox.ini +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: django-import-export
3
- Version: 4.4.2
3
+ Version: 4.4.4
4
4
  Summary: Django application and library for importing and exporting data with included admin integration.
5
5
  Author-email: Bojan Mihelač <djangoimportexport@gmail.com>
6
6
  Maintainer-email: Matthew Hegarty <djangoimportexport@gmail.com>
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: django-import-export
3
- Version: 4.4.2
3
+ Version: 4.4.4
4
4
  Summary: Django application and library for importing and exporting data with included admin integration.
5
5
  Author-email: Bojan Mihelač <djangoimportexport@gmail.com>
6
6
  Maintainer-email: Matthew Hegarty <djangoimportexport@gmail.com>
@@ -0,0 +1,8 @@
1
+ {
2
+ "tag": "4.4.4",
3
+ "distance": 0,
4
+ "node": "gc1c4100281857e8cc03916bc330ae5b6d6e2d173",
5
+ "dirty": false,
6
+ "branch": "HEAD",
7
+ "node_date": "2026-10-27"
8
+ }
@@ -5,11 +5,26 @@ Changelog
5
5
 
6
6
  If upgrading from v3, v4 introduces breaking changes. Please refer to :doc:`release notes<release_notes>`.
7
7
 
8
+ 4.4.4 (2026-10-27)
9
+ -------------------
10
+
11
+ - Fixed ``CSV`` being omitted from the default formats on Python 3.15 because tablib 3.10+ lazily imports ``tablib.core``, leaving the format registry empty when the first ``is_available()`` check runs (`2210 <https://github.com/django-import-export/django-import-export/issues/2210>`_)
12
+ - Fixed ``django.utils.functional.cached_property is deprecated`` warning on Django 6.2 by using ``functools.cached_property``
13
+ - Fixed ``ExportActionMixin.get_actions()`` for Django 6.1, which deprecates overriding it without the new ``action_location`` parameter and, with the old signature, disables all change form actions on the admin. (`2214 <https://github.com/django-import-export/django-import-export/pull/2214>`_)
14
+
15
+ 4.4.3 (2026-10-19)
16
+ -------------------
17
+
18
+ - Fixed a denial-of-service issue where importing a crafted large-magnitude integer value could stall the process during conversion to a Python integer.
19
+ See :ref:`release notes <release_notes_integer_widget_dos>` for details and mitigations.
20
+ (`GHSA-fcgw-hjjv-4rh6 <https://github.com/django-import-export/django-import-export/security/advisories/GHSA-fcgw-hjjv-4rh6>`_)
21
+
8
22
  4.4.2 (2026-10-15)
9
23
  -------------------
10
24
 
11
25
  - Fixed a security and data integrity issue where an import row classified as "new" could silently overwrite an existing database row.
12
26
  See :ref:`release notes <release_notes_force_insert_on_create>` for details and mitigations.
27
+ (`GHSA-8xvj-4m4r-g62h <https://github.com/django-import-export/django-import-export/security/advisories/GHSA-8xvj-4m4r-g62h>`_)
13
28
 
14
29
  4.4.1 (2026-05-05)
15
30
  -------------------
@@ -2,6 +2,49 @@
2
2
  Release Notes
3
3
  =============
4
4
 
5
+ v4.4.3
6
+ ------
7
+
8
+ .. _release_notes_integer_widget_dos:
9
+
10
+ * This release patches a denial-of-service vulnerability in :class:`~import_export.widgets.IntegerWidget`.
11
+
12
+ ``IntegerWidget.clean()`` converted imported values using ``int(Decimal(value))`` with no bound on the
13
+ value's magnitude. A value written in exponent notation, such as ``1e1000000``, is cheap to parse as a
14
+ ``Decimal`` but forces Python to expand every digit when converted to ``int``, a cost that grows
15
+ superlinearly with the digit count. A single such value could stall the importing process for several
16
+ seconds while pinning a CPU core, and a file containing many such rows multiplied the cost.
17
+
18
+ ``IntegerWidget`` is the default widget for all integer model fields, including the ``id`` column used by
19
+ every resource that does not override ``import_id_fields``, so almost every import was affected. The stall
20
+ occurred during the initial dry run, before the confirmation step. Python's
21
+ ``sys.set_int_max_str_digits()`` limit did not protect this path, as it only guards conversions between
22
+ ``int`` and ``str``, not ``Decimal.__int__``.
23
+
24
+ This was an availability issue only. The resulting integers exceed the range of any standard database
25
+ integer column, so no data could be written or corrupted through this path.
26
+
27
+ The fix rejects values whose magnitude exceeds ``sys.get_int_max_str_digits()`` digits (4300 by default)
28
+ before the conversion is attempted. Such values are now reported as row errors. Values within the limit,
29
+ including those in exponent notation such as ``1e5``, are unaffected, and no value a standard integer column
30
+ could store is rejected. All users are advised to upgrade.
31
+
32
+ If you import integers larger than the default limit into a field that can store them, raise the limit with
33
+ ``sys.set_int_max_str_digits()``; the widget honours the configured value.
34
+
35
+ If you subclass :class:`~import_export.widgets.IntegerWidget` and override ``clean()``, you receive this fix
36
+ automatically only if your override delegates to ``super().clean()``. An override that reimplements the
37
+ ``int(Decimal(...))`` conversion itself is not protected, and should apply the same magnitude check before
38
+ converting.
39
+
40
+ If you cannot upgrade, either of the following prevents the stall:
41
+
42
+ - Set :ref:`IMPORT_EXPORT_IMPORT_PERMISSION_CODE` to restrict import access to trusted users.
43
+ - Subclass :class:`~import_export.widgets.IntegerWidget`, override ``clean()`` to reject values whose
44
+ magnitude exceeds a sensible bound before calling ``super().clean()``, and assign the subclass to the
45
+ integer fields on your resources. This suits deployments where all staff legitimately need import
46
+ permission.
47
+
5
48
  v4.4.2
6
49
  ------
7
50
 
@@ -41,6 +84,10 @@ v4.4.2
41
84
  If you have overridden :meth:`~import_export.resources.Resource.do_instance_save`, review it to ensure that
42
85
  ``is_create`` is honoured.
43
86
 
87
+ If any of your models override ``save()``, the override must accept ``*args`` and ``**kwargs`` and pass them to
88
+ ``super().save()``, as required by Django. An override declared as ``def save(self)`` will now fail with a
89
+ ``TypeError`` when a new instance is imported, because ``force_insert`` is passed as a keyword argument.
90
+
44
91
  If you have understood the implications and need to restore the previous behaviour, override
45
92
  :meth:`~import_export.resources.Resource.do_instance_save` to call ``instance.save()`` without ``force_insert``.
46
93
  Note that this reinstates the overwrite described above for your resource.
@@ -18,7 +18,7 @@ version_tuple: tuple[int | str, ...]
18
18
  commit_id: str | None
19
19
  __commit_id__: str | None
20
20
 
21
- __version__ = version = '4.4.2'
22
- __version_tuple__ = version_tuple = (4, 4, 2)
21
+ __version__ = version = '4.4.4'
22
+ __version_tuple__ = version_tuple = (4, 4, 4)
23
23
 
24
- __commit_id__ = commit_id = 'g6c991f289'
24
+ __commit_id__ = commit_id = 'gc1c410028'
@@ -916,6 +916,7 @@ class ExportActionMixin(ExportMixin):
916
916
  )
917
917
  return super().response_change(request, obj)
918
918
 
919
+ @admin.action(description=_("Export selected %(verbose_name_plural)s"))
919
920
  def export_admin_action(self, request, queryset):
920
921
  """
921
922
  Action runs on POST from instance action menu (if enabled).
@@ -959,19 +960,22 @@ class ExportActionMixin(ExportMixin):
959
960
 
960
961
  return render(request, "admin/import_export/export.html", context=context)
961
962
 
962
- def get_actions(self, request):
963
+ def get_actions(self, request, action_location=None):
963
964
  """
964
965
  Adds the export action to the list of available actions.
965
- """
966
- actions = super().get_actions(request)
967
- if self.has_export_permission(request):
968
- actions.update(
969
- export_admin_action=(
970
- type(self).export_admin_action,
971
- "export_admin_action",
972
- _("Export selected %(verbose_name_plural)s"),
973
- )
974
- )
966
+
967
+ ``action_location`` was added in Django 6.1 (``ActionLocation.CHANGE_LIST``
968
+ or ``ActionLocation.CHANGE_FORM``). ``None`` means the change list, which
969
+ is also what Django itself defaults to. The export action is only offered
970
+ on the change list.
971
+ """
972
+ # only forward the parameter when given, so that Django < 6.1 (which
973
+ # does not accept it) keeps working unchanged
974
+ kwargs = {} if action_location is None else {"action_location": action_location}
975
+ actions = super().get_actions(request, **kwargs)
976
+ export_action = self.get_action("export_admin_action", **kwargs)
977
+ if export_action is not None and self.has_export_permission(request):
978
+ actions["export_admin_action"] = export_action
975
979
  return actions
976
980
 
977
981
 
@@ -13,6 +13,19 @@ from tablib.formats import registry
13
13
  logger = logging.getLogger(__name__)
14
14
 
15
15
 
16
+ def _ensure_tablib_registry():
17
+ """
18
+ Make sure tablib's builtin formats are registered.
19
+
20
+ tablib registers its builtin formats as a side effect of importing
21
+ ``tablib.core``. With tablib 3.10+ on Python 3.15+, ``tablib.core`` is a
22
+ lazy module, so the registry can still be empty when a format is first
23
+ looked up (see issue 2210).
24
+ """
25
+ if not registry._formats:
26
+ registry.register_builtins()
27
+
28
+
16
29
  class Format:
17
30
  def get_title(self):
18
31
  return type(self)
@@ -77,6 +90,7 @@ class TablibFormat(Format):
77
90
  if not self.TABLIB_MODULE:
78
91
  raise AttributeError("TABLIB_MODULE must be defined")
79
92
  key = self.TABLIB_MODULE.split(".")[-1].replace("_", "")
93
+ _ensure_tablib_registry()
80
94
  return registry.get_format(key)
81
95
 
82
96
  @classmethod
@@ -2,10 +2,10 @@ import logging
2
2
  import sys
3
3
  import traceback
4
4
  from collections import OrderedDict
5
+ from functools import cached_property
5
6
 
6
7
  from django.core.exceptions import NON_FIELD_ERRORS
7
8
  from django.utils.encoding import force_str
8
- from django.utils.functional import cached_property
9
9
  from django.utils.translation import gettext_lazy as _
10
10
  from tablib import Dataset
11
11
 
@@ -1,6 +1,7 @@
1
1
  import json
2
2
  import logging
3
3
  import numbers
4
+ import sys
4
5
  from collections import defaultdict, namedtuple
5
6
  from datetime import date, datetime, time, timedelta
6
7
  from decimal import Decimal
@@ -168,12 +169,24 @@ class IntegerWidget(NumberWidget):
168
169
  :param row: The current row being processed.
169
170
  :param **kwargs: Optional keyword arguments.
170
171
  :returns: A Python int instance, or None if value is empty.
171
- :raises ValueError: If the value cannot be converted to integer.
172
+ :raises ValueError: If the value cannot be converted to integer, or if
173
+ its magnitude exceeds ``sys.get_int_max_str_digits()`` digits.
172
174
  :raises InvalidOperation: If Decimal conversion fails.
173
175
  """
174
176
  if self.is_empty(value):
175
177
  return None
176
- return int(Decimal(sanitize_separators(value)))
178
+ d = Decimal(sanitize_separators(value))
179
+ # Reject values whose magnitude would make the Decimal-to-int conversion
180
+ # disproportionately expensive. ``sys.set_int_max_str_digits`` does not
181
+ # guard ``Decimal.__int__``, so the same limit is applied explicitly.
182
+ # See GHSA-fcgw-hjjv-4rh6.
183
+ max_digits = sys.get_int_max_str_digits()
184
+ if d.is_finite() and d.adjusted() >= max_digits:
185
+ raise ValueError(
186
+ f"the value's magnitude exceeds the maximum of {max_digits} "
187
+ "digits allowed for integer conversion"
188
+ )
189
+ return int(d)
177
190
 
178
191
 
179
192
  class DecimalWidget(NumberWidget):
@@ -1,6 +1,6 @@
1
1
  import warnings
2
2
  from datetime import date, datetime
3
- from unittest import mock
3
+ from unittest import mock, skipUnless
4
4
  from unittest.mock import MagicMock, PropertyMock, patch
5
5
 
6
6
  from core.admin import CategoryAdmin
@@ -18,6 +18,11 @@ from django.urls import reverse
18
18
 
19
19
  from import_export.admin import ExportMixin
20
20
 
21
+ try:
22
+ from django.contrib.admin.options import ActionLocation
23
+ except ImportError: # Django < 6.1
24
+ ActionLocation = None
25
+
21
26
 
22
27
  class ExportActionAdminIntegrationTest(AdminTestMixin, TestCase):
23
28
  def setUp(self):
@@ -111,8 +116,10 @@ class ExportActionAdminIntegrationTest(AdminTestMixin, TestCase):
111
116
  self.assertEqual(target_str.encode(), response.content)
112
117
 
113
118
  def test_export_admin_action(self):
119
+ # autospec so that Django's get_action() sees a function, not a MagicMock
120
+ # which would answer any attribute lookup (e.g. 'locations')
114
121
  with mock.patch(
115
- "core.admin.CategoryAdmin.export_admin_action"
122
+ "core.admin.CategoryAdmin.export_admin_action", autospec=True
116
123
  ) as mock_export_admin_action:
117
124
  response = self.client.post(
118
125
  self.category_change_url,
@@ -541,3 +548,54 @@ class TestSkipExportFormFromChangeForm(AdminTestMixin, TestCase):
541
548
  )
542
549
  target_re = r"This exporter will export the following fields:"
543
550
  self.assertRegex(response.content.decode(), target_re)
551
+
552
+
553
+ class ExportActionGetActionsTest(AdminTestMixin, TestCase):
554
+ """
555
+ ``get_actions()`` must integrate with Django's action API, which gained an
556
+ ``action_location`` parameter in Django 6.1.
557
+ """
558
+
559
+ def setUp(self):
560
+ super().setUp()
561
+ # the admin only renders the action form when there are results
562
+ Category.objects.create(name="Cat 1")
563
+ self.model_admin = CategoryAdmin(Category, AdminSite())
564
+ self.request = RequestFactory().get(self.category_change_url)
565
+ self.request.user = User.objects.create_superuser(
566
+ "superuser", "superuser@example.com", "password"
567
+ )
568
+
569
+ def test_export_action_in_change_list_actions(self):
570
+ actions = self.model_admin.get_actions(self.request)
571
+ self.assertIn("export_admin_action", actions)
572
+
573
+ def test_export_action_choice_description(self):
574
+ choices = self.model_admin.get_action_choices(self.request)
575
+ self.assertIn(("export_admin_action", "Export selected categories"), choices)
576
+
577
+ @skipUnless(ActionLocation, "requires Django 6.1+")
578
+ def test_export_action_in_change_list_location(self):
579
+ actions = self.model_admin.get_actions(
580
+ self.request, action_location=ActionLocation.CHANGE_LIST
581
+ )
582
+ self.assertIn("export_admin_action", actions)
583
+
584
+ @skipUnless(ActionLocation, "requires Django 6.1+")
585
+ def test_export_action_not_in_change_form_location(self):
586
+ actions = self.model_admin.get_actions(
587
+ self.request, action_location=ActionLocation.CHANGE_FORM
588
+ )
589
+ self.assertNotIn("export_admin_action", actions)
590
+
591
+ @skipUnless(ActionLocation, "requires Django 6.1+")
592
+ def test_change_list_does_not_emit_get_actions_deprecation_warning(self):
593
+ with warnings.catch_warnings():
594
+ warnings.simplefilter("error", DeprecationWarning)
595
+ warnings.simplefilter("error", PendingDeprecationWarning)
596
+ response = self.client.get(self.category_change_url)
597
+ self.assertEqual(200, response.status_code)
598
+ self.assertIn(
599
+ '<option value="export_admin_action">Export selected categories</option>',
600
+ response.content.decode(),
601
+ )
@@ -34,6 +34,14 @@ class FormatTest(TestCase):
34
34
  def test_format_available(self):
35
35
  self.assertTrue(base_formats.CSV.is_available())
36
36
 
37
+ def test_format_available_when_tablib_registry_empty(self):
38
+ # Regression test for issue 2210. With tablib 3.10+ on Python 3.15+,
39
+ # `tablib.core` is a lazy module, so the builtin formats may not have
40
+ # been registered when the first `is_available()` check runs.
41
+ with mock.patch.dict(tablib.formats.registry._formats, clear=True):
42
+ self.assertTrue(base_formats.CSV.is_available())
43
+ self.assertIn("csv", tablib.formats.registry._formats)
44
+
37
45
  def test_get_title(self):
38
46
  self.assertEqual(
39
47
  "<class 'import_export.formats.base_formats.Format'>",
@@ -1,6 +1,8 @@
1
1
  import json
2
+ import sys
2
3
  from datetime import date, datetime, time, timedelta
3
4
  from decimal import Decimal
5
+ from time import process_time
4
6
  from unittest import mock
5
7
  from unittest.mock import patch
6
8
 
@@ -552,6 +554,28 @@ class IntegerWidgetTest(TestCase, RowDeprecationTestMixin):
552
554
  def test_locale_render_gte_django4(self):
553
555
  self.assertEqual(self.widget_coerce_to_string.render(self.value), "0")
554
556
 
557
+ def test_clean_exponent_notation(self):
558
+ # legitimate exponent notation within bounds is still accepted
559
+ self.assertEqual(self.widget.clean("1e5"), 100000)
560
+
561
+ def test_clean_oversized_magnitude_raises(self):
562
+ # a crafted large-exponent value must be rejected rather than stalling
563
+ # the process on an expensive Decimal-to-int conversion (DoS guard).
564
+ start = process_time()
565
+ with self.assertRaises(ValueError):
566
+ self.widget.clean("1e1000000")
567
+ # the guard must trip before any costly conversion is attempted
568
+ self.assertLess(process_time() - start, 1.0)
569
+
570
+ def test_clean_oversized_digit_string_raises(self):
571
+ with self.assertRaises(ValueError):
572
+ self.widget.clean("9" * (sys.get_int_max_str_digits() + 1))
573
+
574
+ def test_clean_at_digit_limit_boundary(self):
575
+ # a value just under the limit is still accepted
576
+ digits = sys.get_int_max_str_digits() - 1
577
+ self.assertEqual(self.widget.clean("9" * digits), int("9" * digits))
578
+
555
579
 
556
580
  class ForeignKeyWidgetTest(TestCase, RowDeprecationTestMixin):
557
581
  def setUp(self):
@@ -1,8 +0,0 @@
1
- {
2
- "tag": "4.4.2",
3
- "distance": 0,
4
- "node": "g6c991f2899cc8fcd776de1eb1f8e0b259c439ba0",
5
- "dirty": false,
6
- "branch": "HEAD",
7
- "node_date": "2026-10-15"
8
- }