Repository: django-import-export/django-import-export (language: python)

Issue:
Upgrade to tablib 4
[tablib 4 is coming](https://github.com/jazzband/tablib/issues/558#issuecomment-1715501213). We should upgrade in v4 due to the breaking changes described [here](https://github.com/jazzband/tablib/issues/558).

At present [test](https://github.com/django-import-export/django-import-export/blob/1c8e38c27abe3f6088da74c6a806e4092c87cd0c/tests/core/tests/test_base_formats.py#L213) is removed until tablib v4 is released.

Note I cannot pin the version to tablib master, because this fails when attempting to upload to testpypi.  The version has to be a valid version.




Discussion / hints:
Just as a side note, the pinned version of `tablib==3.5.0` depends on `MarkupPy`, which uses a deprecated setuptools metadata option (`description-file`). By 26/09/2024, this option will be unsupported by setuptools, meaning trying to install and build (as no wheels are provided) `MarkupPy` will fail.
Since no sign of tablib v4 yet, probably best that I upgrade this in django-import-export v4.2 and document the breaking change.

Fix patch:
diff --git a/docs/changelog.rst b/docs/changelog.rst
index ca893e120..82daa5cd9 100644
--- a/docs/changelog.rst
+++ b/docs/changelog.rst
@@ -11,15 +11,11 @@ Changelog
 
 - Consistent queryset creation in ModelAdmin export mixin (`1890 <https://github.com/django-import-export/django-import-export/pull/1890>`_)
 - Deprecated :meth:`~import_export.admin.ExportMixin.get_valid_export_item_pks` in favour of :meth:`~import_export.admin.ExportMixin.get_queryset` (`1890 <https://github.com/django-import-export/django-import-export/pull/1890>`_)
-- Fix export for fields with custom declared name (`1903 <https://github.com/django-import-export/django-import-export/pull/1903>`_)
-- Hide the “Resource” form when it only has one option, to avoid potentially confusing text in the interface like “Resource: BookResource”.
-  To undo this change, use a form subclass that changes the field’s widget to a ``django.forms.Select``.
-  (`1908 <https://github.com/django-import-export/django-import-export/issues/1908>`__)
-
-4.1.2 (Unreleased)
-------------------
-
 - Improve deprecation warning for ``ExportViewFormMixin`` to report at point of class definition (`1900 <https://github.com/django-import-export/django-import-export/pull/1900>`_)
+- Fix export for fields with custom declared name (`1903 <https://github.com/django-import-export/django-import-export/pull/1903>`_)
+- Hide the "Resource" form when it only has one option (`1908 <https://github.com/django-import-export/django-import-export/issues/1908>`_)
+- Update date, time and datetime widget render method to handle derived instance (`1918 <https://github.com/django-import-export/django-import-export/issues/1918>`_)
+- Upgraded tablib version (`1627 <https://github.com/django-import-export/django-import-export/issues/1627>`_)
 
 4.1.1 (2024-07-08)
 ------------------
diff --git a/docs/release_notes.rst b/docs/release_notes.rst
index 86ab8377d..6299427b4 100644
--- a/docs/release_notes.rst
+++ b/docs/release_notes.rst
@@ -20,6 +20,17 @@ v4.2
   new parameter to :meth:`~import_export.resources.Resource.export_resource` and
   :meth:`~import_export.resources.Resource.get_export_headers`.
 
+* Hide the "Resource" form when it only has one option, to avoid potentially confusing text in the interface like
+  "Resource: BookResource". To undo this change, use a form subclass that changes the field’s widget to a
+  ``django.forms.Select``.  See `1908 <https://github.com/django-import-export/django-import-export/issues/1908>`_
+
+*  `tablib <https://github.com/jazzband/tablib>`_ has been upgraded from v3.5.0 to 3.6.1.
+   This upgrade removes tablib's dependency on `MarkupPy <https://github.com/jazzband/tablib/pull/554>`_ in favour
+   of ElementTree.  If you export to HTML, then this change may affect your output format, particularly if you have
+   already escaped HTML characters in the text.
+
+   See `issue 1627 <https://github.com/django-import-export/django-import-export/issues/1627>`_.
+
 v4.1
 ----
 
diff --git a/pyproject.toml b/pyproject.toml
index cb355052f..966be5756 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -34,16 +34,15 @@ classifiers = [
     "Topic :: Software Development",
 ]
 
-# tablib temporarily using master before v4
 dependencies = [
     "diff-match-patch",
     "Django>=4.2",
-    "tablib==3.5.0"
+    "tablib>=3.6.1"
 ]
 
 [project.optional-dependencies]
 all = [
-    "tablib[all]==3.5.0"
+    "tablib[all]>=3.6.1"
 ]
 cli = ["tablib[cli]"]
 ods = ["tablib[ods]"]
diff --git a/requirements/base.txt b/requirements/base.txt
index 739c47a47..79b607e7a 100644
--- a/requirements/base.txt
+++ b/requirements/base.txt
@@ -1,4 +1,3 @@
 Django>=3.2
-# # tablib temporarily pinned before v4 - see #1627
-tablib==3.5.0
+tablib>=3.6.1
 diff-match-patch


Test patch:
diff --git a/tests/core/tests/test_base_formats.py b/tests/core/tests/test_base_formats.py
index 9550c0026..475804081 100644
--- a/tests/core/tests/test_base_formats.py
+++ b/tests/core/tests/test_base_formats.py
@@ -213,21 +213,20 @@ def setUp(self):
             )
         )
 
-    # TODO removed pending tablib v4 - see #1627
-    # def test_export_html_escape(self):
-    #     res = self.format.export_data(self.dataset)
-    #     self.assertIn(
-    #         (
-    #             "<tr><td>1</td>"
-    #             "<td>good_user</td>"
-    #             "<td>John Doe</td></tr>"
-    #             "<tr><td>2</td>"
-    #             "<td>evil_user</td>"
-    #             '<td>&lt;script&gt;alert("I want to steal your credit card data")'
-    #             "&lt;/script&gt;</td></tr>"
-    #         ),
-    #         res,
-    #     )
+    def test_export_html_escape(self):
+        res = self.format.export_data(self.dataset)
+        self.assertIn(
+            (
+                "<tr><td>1</td>"
+                "<td>good_user</td>"
+                "<td>John Doe</td></tr>"
+                "<tr><td>2</td>"
+                "<td>evil_user</td>"
+                '<td>&lt;script&gt;alert("I want to steal your credit card data")'
+                "&lt;/script&gt;</td></tr>"
+            ),
+            res,
+        )
 
 
 class YAMLFormatTest(TestCase):