codecov[bot]: # [Codecov](https://codecov.io/gh/scrapy/scrapy/pull/4668?src=pr&el=h1) Report
> Merging [#4668](https://codecov.io/gh/scrapy/scrapy/pull/4668?src=pr&el=desc) into [master](https://codecov.io/gh/scrapy/scrapy/commit/56a6d22352071208637abd86bd7b6d81a50d5bdb&el=desc) will **decrease** coverage by `0.01%`.
> The diff coverage is `100.00%`.


```diff
@@            Coverage Diff             @@
##           master    #4668      +/-   ##
==========================================
- Coverage   84.80%   84.79%   -0.02%     
==========================================
  Files         163      163              
  Lines        9990     9988       -2     
  Branches     1488     1487       -1     
==========================================
- Hits         8472     8469       -3     
  Misses       1255     1255              
- Partials      263      264       +1     
```

| [Impacted Files](https://codecov.io/gh/scrapy/scrapy/pull/4668?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [scrapy/exporters.py](https://codecov.io/gh/scrapy/scrapy/pull/4668/diff?src=pr&el=tree#diff-c2NyYXB5L2V4cG9ydGVycy5weQ==) | `100.00% <100.00%> (ø)` | |
| [scrapy/utils/trackref.py](https://codecov.io/gh/scrapy/scrapy/pull/4668/diff?src=pr&el=tree#diff-c2NyYXB5L3V0aWxzL3RyYWNrcmVmLnB5) | `82.85% <0.00%> (-2.86%)` | :arrow_down: |

diff --git a/scrapy/exporters.py b/scrapy/exporters.py
index 712572673..0aba1c904 100644
--- a/scrapy/exporters.py
+++ b/scrapy/exporters.py
@@ -243,12 +243,8 @@ class CsvItemExporter(BaseItemExporter):
     def _write_headers_and_set_fields_to_export(self, item):
         if self.include_headers_line:
             if not self.fields_to_export:
-                if isinstance(item, dict):
-                    # for dicts try using fields of the first item
-                    self.fields_to_export = list(item.keys())
-                else:
-                    # use fields declared in Item
-                    self.fields_to_export = list(item.fields.keys())
+                # use declared field names, or keys if the item is a dict
+                self.fields_to_export = ItemAdapter(item).field_names()
             row = list(self._build_row(self.fields_to_export))
             self.csv_writer.writerow(row)
 
diff --git a/setup.cfg b/setup.cfg
index 46a3d13fc..f8e7c0c91 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -13,9 +13,6 @@ follow_imports = skip
 [mypy-scrapy]
 ignore_errors = True
 
-[mypy-scrapy._monkeypatches]
-ignore_errors = True
-
 [mypy-scrapy.commands]
 ignore_errors = True
 

List of fields incorrectly accessed for dataclass items
### Description

If I make a `dataclass` item and want to export to csv, I get this error:

```
...
  File "/home/tadej/miniconda3/envs/main/lib/python3.7/site-packages/scrapy/exporters.py", line 251, in _write_headers_and_set_fields_to_export
    self.fields_to_export = list(item.fields.keys())
AttributeError: 'CompanyItem' object has no attribute 'fields'
```
The problem stems from here

https://github.com/scrapy/scrapy/blob/master/scrapy/exporters.py#L243-L253

There should be an additional if case checking if the item is of type dataclass, and then accessing the fields differently, perhaps as
```python
[field.name for field in fields(item)]
```

diff --git a/tests/test_exporters.py b/tests/test_exporters.py
index b27380309..25da54a65 100644
--- a/tests/test_exporters.py
+++ b/tests/test_exporters.py
@@ -8,6 +8,7 @@ from io import BytesIO
 from datetime import datetime
 
 import lxml.etree
+from itemadapter import ItemAdapter
 
 from scrapy.item import Item, Field
 from scrapy.utils.python import to_unicode
@@ -23,10 +24,37 @@ class TestItem(Item):
     age = Field()
 
 
+def custom_serializer(value):
+    return str(int(value) + 2)
+
+
+class CustomFieldItem(Item):
+    name = Field()
+    age = Field(serializer=custom_serializer)
+
+
+try:
+    from dataclasses import make_dataclass, field
+except ImportError:
+    TestDataClass = None
+    CustomFieldDataclass = None
+else:
+    TestDataClass = make_dataclass("TestDataClass", [("name", str), ("age", int)])
+    CustomFieldDataclass = make_dataclass(
+        "CustomFieldDataclass",
+        [("name", str), ("age", int, field(metadata={"serializer": custom_serializer}))]
+    )
+
+
 class BaseItemExporterTest(unittest.TestCase):
 
+    item_class = TestItem
+    custom_field_item_class = CustomFieldItem
+
     def setUp(self):
-        self.i = TestItem(name=u'John\xa3', age=u'22')
+        if self.item_class is None:
+            raise unittest.SkipTest("item class is None")
+        self.i = self.item_class(name=u'John\xa3', age=u'22')
         self.output = BytesIO()
         self.ie = self._get_exporter()
 
@@ -39,7 +67,7 @@ class BaseItemExporterTest(unittest.TestCase):
     def _assert_expected_item(self, exported_dict):
         for k, v in exported_dict.items():
             exported_dict[k] = to_unicode(v)
-        self.assertEqual(self.i, exported_dict)
+        self.assertEqual(self.i, self.item_class(**exported_dict))
 
     def _get_nonstring_types_item(self):
         return {
@@ -63,13 +91,14 @@ class BaseItemExporterTest(unittest.TestCase):
         self.assertItemExportWorks(self.i)
 
     def test_export_dict_item(self):
-        self.assertItemExportWorks(dict(self.i))
+        self.assertItemExportWorks(ItemAdapter(self.i).asdict())
 
     def test_serialize_field(self):
-        res = self.ie.serialize_field(self.i.fields['name'], 'name', self.i['name'])
+        a = ItemAdapter(self.i)
+        res = self.ie.serialize_field(a.get_field_meta('name'), 'name', a['name'])
         self.assertEqual(res, u'John\xa3')
 
-        res = self.ie.serialize_field(self.i.fields['age'], 'age', self.i['age'])
+        res = self.ie.serialize_field(a.get_field_meta('age'), 'age', a['age'])
         self.assertEqual(res, u'22')
 
     def test_fields_to_export(self):
@@ -82,18 +111,16 @@ class BaseItemExporterTest(unittest.TestCase):
         self.assertEqual(name, u'John\xa3')
 
     def test_field_custom_serializer(self):
-        def custom_serializer(value):
-            return str(int(value) + 2)
-
-        class CustomFieldItem(Item):
-            name = Field()
-            age = Field(serializer=custom_serializer)
+        i = self.custom_field_item_class(name=u'John\xa3', age=u'22')
+        a = ItemAdapter(i)
+        ie = self._get_exporter()
+        self.assertEqual(ie.serialize_field(a.get_field_meta('name'), 'name', a['name']), u'John\xa3')
+        self.assertEqual(ie.serialize_field(a.get_field_meta('age'), 'age', a['age']), '24')
 
-        i = CustomFieldItem(name=u'John\xa3', age=u'22')
 
-        ie = self._get_exporter()
-        self.assertEqual(ie.serialize_field(i.fields['name'], 'name', i['name']), u'John\xa3')
-        self.assertEqual(ie.serialize_field(i.fields['age'], 'age', i['age']), '24')
+class BaseItemExporterDataclassTest(BaseItemExporterTest):
+    item_class = TestDataClass
+    custom_field_item_class = CustomFieldDataclass
 
 
 class PythonItemExporterTest(BaseItemExporterTest):
@@ -105,9 +132,9 @@ class PythonItemExporterTest(BaseItemExporterTest):
             PythonItemExporter(invalid_option='something')
 
     def test_nested_item(self):
-        i1 = TestItem(name=u'Joseph', age='22')
+        i1 = self.item_class(name=u'Joseph', age='22')
         i2 = dict(name=u'Maria', age=i1)
-        i3 = TestItem(name=u'Jesus', age=i2)
+        i3 = self.item_class(name=u'Jesus', age=i2)
         ie = self._get_exporter()
         exported = ie.export_item(i3)
         self.assertEqual(type(exported), dict)
@@ -119,9 +146,9 @@ class PythonItemExporterTest(BaseItemExporterTest):
         self.assertEqual(type(exported['age']['age']), dict)
 
     def test_export_list(self):
-        i1 = TestItem(name=u'Joseph', age='22')
-        i2 = TestItem(name=u'Maria', age=[i1])
-        i3 = TestItem(name=u'Jesus', age=[i2])
+        i1 = self.item_class(name=u'Joseph', age='22')
+        i2 = self.item_class(name=u'Maria', age=[i1])
+        i3 = self.item_class(name=u'Jesus', age=[i2])
         ie = self._get_exporter()
         exported = ie.export_item(i3)
         self.assertEqual(
@@ -132,9 +159,9 @@ class PythonItemExporterTest(BaseItemExporterTest):
         self.assertEqual(type(exported['age'][0]['age'][0]), dict)
 
     def test_export_item_dict_list(self):
-        i1 = TestItem(name=u'Joseph', age='22')
+        i1 = self.item_class(name=u'Joseph', age='22')
         i2 = dict(name=u'Maria', age=[i1])
-        i3 = TestItem(name=u'Jesus', age=[i2])
+        i3 = self.item_class(name=u'Jesus', age=[i2])
         ie = self._get_exporter()
         exported = ie.export_item(i3)
         self.assertEqual(
@@ -146,7 +173,7 @@ class PythonItemExporterTest(BaseItemExporterTest):
 
     def test_export_binary(self):
         exporter = PythonItemExporter(binary=True)
-        value = TestItem(name=u'John\xa3', age=u'22')
+        value = self.item_class(name=u'John\xa3', age=u'22')
         expected = {b'name': b'John\xc2\xa3', b'age': b'22'}
         self.assertEqual(expected, exporter.export_item(value))
 
@@ -157,6 +184,11 @@ class PythonItemExporterTest(BaseItemExporterTest):
         self.assertEqual(exported, item)
 
 
+class PythonItemExporterDataclassTest(PythonItemExporterTest):
+    item_class = TestDataClass
+    custom_field_item_class = CustomFieldDataclass
+
+
 class PprintItemExporterTest(BaseItemExporterTest):
 
     def _get_exporter(self, **kwargs):
@@ -166,6 +198,11 @@ class PprintItemExporterTest(BaseItemExporterTest):
         self._assert_expected_item(eval(self.output.getvalue()))
 
 
+class PprintItemExporterDataclassTest(PprintItemExporterTest):
+    item_class = TestDataClass
+    custom_field_item_class = CustomFieldDataclass
+
+
 class PickleItemExporterTest(BaseItemExporterTest):
 
     def _get_exporter(self, **kwargs):
@@ -175,8 +212,8 @@ class PickleItemExporterTest(BaseItemExporterTest):
         self._assert_expected_item(pickle.loads(self.output.getvalue()))
 
     def test_export_multiple_items(self):
-        i1 = TestItem(name='hello', age='world')
-        i2 = TestItem(name='bye', age='world')
+        i1 = self.item_class(name='hello', age='world')
+        i2 = self.item_class(name='bye', age='world')
         f = BytesIO()
         ie = PickleItemExporter(f)
         ie.start_exporting()
@@ -184,8 +221,8 @@ class PickleItemExporterTest(BaseItemExporterTest):
         ie.export_item(i2)
         ie.finish_exporting()
         f.seek(0)
-        self.assertEqual(pickle.load(f), i1)
-        self.assertEqual(pickle.load(f), i2)
+        self.assertEqual(self.item_class(**pickle.load(f)), i1)
+        self.assertEqual(self.item_class(**pickle.load(f)), i2)
 
     def test_nonstring_types_item(self):
         item = self._get_nonstring_types_item()
@@ -197,6 +234,11 @@ class PickleItemExporterTest(BaseItemExporterTest):
         self.assertEqual(pickle.loads(fp.getvalue()), item)
 
 
+class PickleItemExporterDataclassTest(PickleItemExporterTest):
+    item_class = TestDataClass
+    custom_field_item_class = CustomFieldDataclass
+
+
 class MarshalItemExporterTest(BaseItemExporterTest):
 
     def _get_exporter(self, **kwargs):
@@ -219,6 +261,11 @@ class MarshalItemExporterTest(BaseItemExporterTest):
         self.assertEqual(marshal.load(fp), item)
 
 
+class MarshalItemExporterDataclassTest(MarshalItemExporterTest):
+    item_class = TestDataClass
+    custom_field_item_class = CustomFieldDataclass
+
+
 class CsvItemExporterTest(BaseItemExporterTest):
     def _get_exporter(self, **kwargs):
         return CsvItemExporter(self.output, **kwargs)
@@ -245,18 +292,18 @@ class CsvItemExporterTest(BaseItemExporterTest):
     def test_header_export_all(self):
         self.assertExportResult(
             item=self.i,
-            fields_to_export=self.i.fields.keys(),
+            fields_to_export=ItemAdapter(self.i).field_names(),
             expected=b'age,name\r\n22,John\xc2\xa3\r\n',
         )
 
     def test_header_export_all_dict(self):
         self.assertExportResult(
-            item=dict(self.i),
+            item=ItemAdapter(self.i).asdict(),
             expected=b'age,name\r\n22,John\xc2\xa3\r\n',
         )
 
     def test_header_export_single_field(self):
-        for item in [self.i, dict(self.i)]:
+        for item in [self.i, ItemAdapter(self.i).asdict()]:
             self.assertExportResult(
                 item=item,
                 fields_to_export=['age'],
@@ -264,7 +311,7 @@ class CsvItemExporterTest(BaseItemExporterTest):
             )
 
     def test_header_export_two_items(self):
-        for item in [self.i, dict(self.i)]:
+        for item in [self.i, ItemAdapter(self.i).asdict()]:
             output = BytesIO()
             ie = CsvItemExporter(output)
             ie.start_exporting()
@@ -275,7 +322,7 @@ class CsvItemExporterTest(BaseItemExporterTest):
                                 b'age,name\r\n22,John\xc2\xa3\r\n22,John\xc2\xa3\r\n')
 
     def test_header_no_header_line(self):
-        for item in [self.i, dict(self.i)]:
+        for item in [self.i, ItemAdapter(self.i).asdict()]:
             self.assertExportResult(
                 item=item,
                 include_headers_line=False,
@@ -309,6 +356,11 @@ class CsvItemExporterTest(BaseItemExporterTest):
         )
 
 
+class CsvItemExporterDataclassTest(CsvItemExporterTest):
+    item_class = TestDataClass
+    custom_field_item_class = CustomFieldDataclass
+
+
 class XmlItemExporterTest(BaseItemExporterTest):
 
     def _get_exporter(self, **kwargs):
@@ -318,8 +370,7 @@ class XmlItemExporterTest(BaseItemExporterTest):
         def xmltuple(elem):
             children = list(elem.iterchildren())
             if children:
-                return [(child.tag, sorted(xmltuple(child)))
-                        for child in children]
+                return [(child.tag, sorted(xmltuple(child))) for child in children]
             else:
                 return [(elem.tag, [(elem.text, ())])]
 
@@ -345,17 +396,21 @@ class XmlItemExporterTest(BaseItemExporterTest):
 
     def test_multivalued_fields(self):
         self.assertExportResult(
-            TestItem(name=[u'John\xa3', u'Doe']),
-            (
-                b'<?xml version="1.0" encoding="utf-8"?>\n'
-                b'<items><item><name><value>John\xc2\xa3</value><value>Doe</value></name></item></items>'
-            )
+            self.item_class(name=[u'John\xa3', u'Doe'], age=[1, 2, 3]),
+            b"""<?xml version="1.0" encoding="utf-8"?>\n
+            <items>
+                <item>
+                    <name><value>John\xc2\xa3</value><value>Doe</value></name>
+                    <age><value>1</value><value>2</value><value>3</value></age>
+                </item>
+            </items>
+            """
         )
 
     def test_nested_item(self):
-        i1 = TestItem(name=u'foo\xa3hoo', age='22')
+        i1 = dict(name=u'foo\xa3hoo', age='22')
         i2 = dict(name=u'bar', age=i1)
-        i3 = TestItem(name=u'buz', age=i2)
+        i3 = self.item_class(name=u'buz', age=i2)
 
         self.assertExportResult(
             i3,
@@ -376,9 +431,9 @@ class XmlItemExporterTest(BaseItemExporterTest):
         )
 
     def test_nested_list_item(self):
-        i1 = TestItem(name=u'foo')
+        i1 = dict(name=u'foo')
         i2 = dict(name=u'bar', v2={"egg": ["spam"]})
-        i3 = TestItem(name=u'buz', age=[i1, i2])
+        i3 = self.item_class(name=u'buz', age=[i1, i2])
 
         self.assertExportResult(
             i3,
@@ -412,6 +467,12 @@ class XmlItemExporterTest(BaseItemExporterTest):
         )
 
 
+class XmlItemExporterDataclassTest(XmlItemExporterTest):
+
+    item_class = TestDataClass
+    custom_field_item_class = CustomFieldDataclass
+
+
 class JsonLinesItemExporterTest(BaseItemExporterTest):
 
     _expected_nested = {'name': u'Jesus', 'age': {'name': 'Maria', 'age': {'name': 'Joseph', 'age': '22'}}}
@@ -421,12 +482,12 @@ class JsonLinesItemExporterTest(BaseItemExporterTest):
 
     def _check_output(self):
         exported = json.loads(to_unicode(self.output.getvalue().strip()))
-        self.assertEqual(exported, dict(self.i))
+        self.assertEqual(exported, ItemAdapter(self.i).asdict())
 
     def test_nested_item(self):
-        i1 = TestItem(name=u'Joseph', age='22')
+        i1 = self.item_class(name=u'Joseph', age='22')
         i2 = dict(name=u'Maria', age=i1)
-        i3 = TestItem(name=u'Jesus', age=i2)
+        i3 = self.item_class(name=u'Jesus', age=i2)
         self.ie.start_exporting()
         self.ie.export_item(i3)
         self.ie.finish_exporting()
@@ -449,6 +510,12 @@ class JsonLinesItemExporterTest(BaseItemExporterTest):
         self.assertEqual(exported, item)
 
 
+class JsonLinesItemExporterDataclassTest(JsonLinesItemExporterTest):
+
+    item_class = TestDataClass
+    custom_field_item_class = CustomFieldDataclass
+
+
 class JsonItemExporterTest(JsonLinesItemExporterTest):
 
     _expected_nested = [JsonLinesItemExporterTest._expected_nested]
@@ -458,7 +525,7 @@ class JsonItemExporterTest(JsonLinesItemExporterTest):
 
     def _check_output(self):
         exported = json.loads(to_unicode(self.output.getvalue().strip()))
-        self.assertEqual(exported, [dict(self.i)])
+        self.assertEqual(exported, [ItemAdapter(self.i).asdict()])
 
     def assertTwoItemsExported(self, item):
         self.ie.start_exporting()
@@ -466,28 +533,28 @@ class JsonItemExporterTest(JsonLinesItemExporterTest):
         self.ie.export_item(item)
         self.ie.finish_exporting()
         exported = json.loads(to_unicode(self.output.getvalue()))
-        self.assertEqual(exported, [dict(item), dict(item)])
+        self.assertEqual(exported, [ItemAdapter(item).asdict(), ItemAdapter(item).asdict()])
 
     def test_two_items(self):
         self.assertTwoItemsExported(self.i)
 
     def test_two_dict_items(self):
-        self.assertTwoItemsExported(dict(self.i))
+        self.assertTwoItemsExported(ItemAdapter(self.i).asdict())
 
     def test_nested_item(self):
-        i1 = TestItem(name=u'Joseph\xa3', age='22')
-        i2 = TestItem(name=u'Maria', age=i1)
-        i3 = TestItem(name=u'Jesus', age=i2)
+        i1 = self.item_class(name=u'Joseph\xa3', age='22')
+        i2 = self.item_class(name=u'Maria', age=i1)
+        i3 = self.item_class(name=u'Jesus', age=i2)
         self.ie.start_exporting()
         self.ie.export_item(i3)
         self.ie.finish_exporting()
         exported = json.loads(to_unicode(self.output.getvalue()))
-        expected = {'name': u'Jesus', 'age': {'name': 'Maria', 'age': dict(i1)}}
+        expected = {'name': u'Jesus', 'age': {'name': 'Maria', 'age': ItemAdapter(i1).asdict()}}
         self.assertEqual(exported, [expected])
 
     def test_nested_dict_item(self):
         i1 = dict(name=u'Joseph\xa3', age='22')
-        i2 = TestItem(name=u'Maria', age=i1)
+        i2 = self.item_class(name=u'Maria', age=i1)
         i3 = dict(name=u'Jesus', age=i2)
         self.ie.start_exporting()
         self.ie.export_item(i3)
@@ -506,7 +573,19 @@ class JsonItemExporterTest(JsonLinesItemExporterTest):
         self.assertEqual(exported, [item])
 
 
-class CustomItemExporterTest(unittest.TestCase):
+class JsonItemExporterDataclassTest(JsonItemExporterTest):
+
+    item_class = TestDataClass
+    custom_field_item_class = CustomFieldDataclass
+
+
+class CustomExporterItemTest(unittest.TestCase):
+
+    item_class = TestItem
+
+    def setUp(self):
+        if self.item_class is None:
+            raise unittest.SkipTest("item class is None")
 
     def test_exporter_custom_serializer(self):
         class CustomItemExporter(BaseItemExporter):
@@ -516,16 +595,22 @@ class CustomItemExporterTest(unittest.TestCase):
                 else:
                     return super(CustomItemExporter, self).serialize_field(field, name, value)
 
-        i = TestItem(name=u'John', age='22')
+        i = self.item_class(name=u'John', age='22')
+        a = ItemAdapter(i)
         ie = CustomItemExporter()
 
-        self.assertEqual(ie.serialize_field(i.fields['name'], 'name', i['name']), 'John')
-        self.assertEqual(ie.serialize_field(i.fields['age'], 'age', i['age']), '23')
+        self.assertEqual(ie.serialize_field(a.get_field_meta('name'), 'name', a['name']), 'John')
+        self.assertEqual(ie.serialize_field(a.get_field_meta('age'), 'age', a['age']), '23')
 
         i2 = {'name': u'John', 'age': '22'}
         self.assertEqual(ie.serialize_field({}, 'name', i2['name']), 'John')
         self.assertEqual(ie.serialize_field({}, 'age', i2['age']), '23')
 
 
+class CustomExporterDataclassTest(CustomExporterItemTest):
+
+    item_class = TestDataClass
+
+
 if __name__ == '__main__':
     unittest.main()

pip install -e .[dev]
parse_log_pytest
requirements.txt
pytest pytest-cov pytest-xdist pytest-mock pytest-asyncio pytest
apt-get update apt-get install -y gcc libxml2-dev libxslt1-dev zlib1g-dev libffi-dev libssl-dev python3-dev
3.9
tests/requirements-py3.txt
pytest --no-header -rA --tb=line --color=no -p no:cacheprovider -W ignore::DeprecationWarning
asgiref==3.5.2
asttokens==3.0.0
attrs==25.3.0
Automat==24.8.1
blessed==1.20.0
bpython==0.25
Brotli==1.0.9
brotlipy==0.7.0
certifi==2025.1.31
cffi==1.17.1
charset-normalizer==3.4.1
click==8.1.8
constantly==23.10.4
coverage==7.8.0
cryptography==38.0.4
cssselect==1.3.0
curtsies==0.4.2
cwcwidth==0.1.10
decorator==5.2.1
exceptiongroup==1.2.2
execnet==2.1.1
executing==2.2.0
Flask==2.2.5
greenlet==3.1.1
h11==0.14.0
h2==4.2.0
hpack==4.1.0
hyperframe==6.1.0
hyperlink==21.0.0
idna==3.10
importlib_metadata==8.6.1
importlib_resources==6.5.2
incremental==24.7.2
iniconfig==2.1.0
ipython==8.18.1
itemadapter==0.11.0
itemloaders==1.3.2
itsdangerous==2.2.0
jedi==0.19.2
Jinja2==3.1.6
jmespath==1.0.1
kaitaistruct==0.10
ldap3==2.9.1
lxml==5.3.1
MarkupSafe==3.0.2
matplotlib-inline==0.1.7
mitmproxy==9.0.1
mitmproxy_wireguard==0.1.23
msgpack==1.0.8
packaging==24.2
parsel==1.10.0
parso==0.8.4
passlib==1.7.4
pexpect==4.9.0
pluggy==1.5.0
prompt_toolkit==3.0.50
Protego==0.4.0
protobuf==4.25.6
ptyprocess==0.7.0
publicsuffix2==2.20191221
pure_eval==0.2.3
pyasn1==0.6.1
pyasn1_modules==0.4.2
pycparser==2.22
PyDispatcher==2.0.7
Pygments==2.19.1
pyOpenSSL==22.1.0
pyparsing==3.0.9
pyperclip==1.8.2
pytest==8.3.5
pytest-asyncio==0.26.0
pytest-azurepipelines==1.0.5
pytest-cov==6.0.0
pytest-mock==3.14.0
pytest-nunit==1.0.7
pytest-twisted==1.14.3
pytest-xdist==3.6.1
pyxdg==0.28
queuelib==1.7.0
requests==2.32.3
ruamel.yaml==0.17.40
ruamel.yaml.clib==0.2.12
-e git+https://github.com/scrapy/scrapy.git@f3372a3753643fea601564c01fcf65cc25a2db62#egg=Scrapy
service-identity==24.2.0
six==1.17.0
sortedcontainers==2.4.0
stack-data==0.6.3
sybil==9.1.0
testfixtures==8.3.0
tomli==2.2.1
tornado==6.4.2
traitlets==5.14.3
Twisted==24.11.0
typing_extensions==4.13.0
urllib3==2.3.0
urwid==2.1.2
w3lib==2.3.1
wcwidth==0.2.13
Werkzeug==3.1.3
wsproto==1.2.0
zipp==3.21.0
zope.interface==7.2
zstandard==0.19.0

name: scrapy
channels:
  - defaults
  - https://repo.anaconda.com/pkgs/main
  - https://repo.anaconda.com/pkgs/r
  - conda-forge
dependencies:
  - _libgcc_mutex=0.1=main
  - _openmp_mutex=5.1=1_gnu
  - ca-certificates=2025.2.25=h06a4308_0
  - ld_impl_linux-64=2.40=h12ee557_0
  - libffi=3.4.4=h6a678d5_1
  - libgcc-ng=11.2.0=h1234567_1
  - libgomp=11.2.0=h1234567_1
  - libstdcxx-ng=11.2.0=h1234567_1
  - ncurses=6.4=h6a678d5_0
  - openssl=3.0.16=h5eee18b_0
  - pip=25.0=py39h06a4308_0
  - python=3.9.21=he870216_1
  - readline=8.2=h5eee18b_0
  - setuptools=75.8.0=py39h06a4308_0
  - sqlite=3.45.3=h5eee18b_0
  - tk=8.6.14=h39e8969_0
  - tzdata=2025a=h04d1e81_0
  - wheel=0.45.1=py39h06a4308_0
  - xz=5.6.4=h5eee18b_1
  - zlib=1.2.13=h5eee18b_1
  - pip:
      - asgiref==3.5.2
      - asttokens==3.0.0
      - attrs==25.3.0
      - automat==24.8.1
      - blessed==1.20.0
      - bpython==0.25
      - brotli==1.0.9
      - brotlipy==0.7.0
      - certifi==2025.1.31
      - cffi==1.17.1
      - charset-normalizer==3.4.1
      - click==8.1.8
      - constantly==23.10.4
      - coverage==7.8.0
      - cryptography==38.0.4
      - cssselect==1.3.0
      - curtsies==0.4.2
      - cwcwidth==0.1.10
      - decorator==5.2.1
      - exceptiongroup==1.2.2
      - execnet==2.1.1
      - executing==2.2.0
      - flask==2.2.5
      - greenlet==3.1.1
      - h11==0.14.0
      - h2==4.2.0
      - hpack==4.1.0
      - hyperframe==6.1.0
      - hyperlink==21.0.0
      - idna==3.10
      - importlib-metadata==8.6.1
      - importlib-resources==6.5.2
      - incremental==24.7.2
      - iniconfig==2.1.0
      - ipython==8.18.1
      - itemadapter==0.11.0
      - itemloaders==1.3.2
      - itsdangerous==2.2.0
      - jedi==0.19.2
      - jinja2==3.1.6
      - jmespath==1.0.1
      - kaitaistruct==0.10
      - ldap3==2.9.1
      - lxml==5.3.1
      - markupsafe==3.0.2
      - matplotlib-inline==0.1.7
      - mitmproxy==9.0.1
      - mitmproxy-wireguard==0.1.23
      - msgpack==1.0.8
      - packaging==24.2
      - parsel==1.10.0
      - parso==0.8.4
      - passlib==1.7.4
      - pexpect==4.9.0
      - pluggy==1.5.0
      - prompt-toolkit==3.0.50
      - protego==0.4.0
      - protobuf==4.25.6
      - ptyprocess==0.7.0
      - publicsuffix2==2.20191221
      - pure-eval==0.2.3
      - pyasn1==0.6.1
      - pyasn1-modules==0.4.2
      - pycparser==2.22
      - pydispatcher==2.0.7
      - pygments==2.19.1
      - pyopenssl==22.1.0
      - pyparsing==3.0.9
      - pyperclip==1.8.2
      - pytest==8.3.5
      - pytest-asyncio==0.26.0
      - pytest-azurepipelines==1.0.5
      - pytest-cov==6.0.0
      - pytest-mock==3.14.0
      - pytest-nunit==1.0.7
      - pytest-twisted==1.14.3
      - pytest-xdist==3.6.1
      - pyxdg==0.28
      - queuelib==1.7.0
      - requests==2.32.3
      - ruamel-yaml==0.17.40
      - ruamel-yaml-clib==0.2.12
      - service-identity==24.2.0
      - six==1.17.0
      - sortedcontainers==2.4.0
      - stack-data==0.6.3
      - sybil==9.1.0
      - testfixtures==8.3.0
      - tomli==2.2.1
      - tornado==6.4.2
      - traitlets==5.14.3
      - twisted==24.11.0
      - typing-extensions==4.13.0
      - urllib3==2.3.0
      - urwid==2.1.2
      - w3lib==2.3.1
      - wcwidth==0.2.13
      - werkzeug==3.1.3
      - wsproto==1.2.0
      - zipp==3.21.0
      - zope-interface==7.2
      - zstandard==0.19.0
prefix: /opt/conda/envs/scrapy

tests/test_exporters.py::CsvItemExporterDataclassTest::test_export_item tests/test_exporters.py::CsvItemExporterDataclassTest::test_header_export_two_items
tests/test_exporters.py::BaseItemExporterTest::test_export_dict_item tests/test_exporters.py::BaseItemExporterTest::test_export_item tests/test_exporters.py::BaseItemExporterTest::test_field_custom_serializer tests/test_exporters.py::BaseItemExporterTest::test_fields_to_export tests/test_exporters.py::BaseItemExporterTest::test_serialize_field tests/test_exporters.py::BaseItemExporterDataclassTest::test_export_dict_item tests/test_exporters.py::BaseItemExporterDataclassTest::test_export_item tests/test_exporters.py::BaseItemExporterDataclassTest::test_field_custom_serializer tests/test_exporters.py::BaseItemExporterDataclassTest::test_fields_to_export tests/test_exporters.py::BaseItemExporterDataclassTest::test_serialize_field tests/test_exporters.py::PythonItemExporterTest::test_export_binary tests/test_exporters.py::PythonItemExporterTest::test_export_dict_item tests/test_exporters.py::PythonItemExporterTest::test_export_item tests/test_exporters.py::PythonItemExporterTest::test_export_item_dict_list tests/test_exporters.py::PythonItemExporterTest::test_export_list tests/test_exporters.py::PythonItemExporterTest::test_field_custom_serializer tests/test_exporters.py::PythonItemExporterTest::test_fields_to_export tests/test_exporters.py::PythonItemExporterTest::test_invalid_option tests/test_exporters.py::PythonItemExporterTest::test_nested_item tests/test_exporters.py::PythonItemExporterTest::test_nonstring_types_item tests/test_exporters.py::PythonItemExporterTest::test_serialize_field tests/test_exporters.py::PythonItemExporterDataclassTest::test_export_binary tests/test_exporters.py::PythonItemExporterDataclassTest::test_export_dict_item tests/test_exporters.py::PythonItemExporterDataclassTest::test_export_item tests/test_exporters.py::PythonItemExporterDataclassTest::test_export_item_dict_list tests/test_exporters.py::PythonItemExporterDataclassTest::test_export_list tests/test_exporters.py::PythonItemExporterDataclassTest::test_field_custom_serializer tests/test_exporters.py::PythonItemExporterDataclassTest::test_fields_to_export tests/test_exporters.py::PythonItemExporterDataclassTest::test_invalid_option tests/test_exporters.py::PythonItemExporterDataclassTest::test_nested_item tests/test_exporters.py::PythonItemExporterDataclassTest::test_nonstring_types_item tests/test_exporters.py::PythonItemExporterDataclassTest::test_serialize_field tests/test_exporters.py::PprintItemExporterTest::test_export_dict_item tests/test_exporters.py::PprintItemExporterTest::test_export_item tests/test_exporters.py::PprintItemExporterTest::test_field_custom_serializer tests/test_exporters.py::PprintItemExporterTest::test_fields_to_export tests/test_exporters.py::PprintItemExporterTest::test_serialize_field tests/test_exporters.py::PprintItemExporterDataclassTest::test_export_dict_item tests/test_exporters.py::PprintItemExporterDataclassTest::test_export_item tests/test_exporters.py::PprintItemExporterDataclassTest::test_field_custom_serializer tests/test_exporters.py::PprintItemExporterDataclassTest::test_fields_to_export tests/test_exporters.py::PprintItemExporterDataclassTest::test_serialize_field tests/test_exporters.py::PickleItemExporterTest::test_export_dict_item tests/test_exporters.py::PickleItemExporterTest::test_export_item tests/test_exporters.py::PickleItemExporterTest::test_export_multiple_items tests/test_exporters.py::PickleItemExporterTest::test_field_custom_serializer tests/test_exporters.py::PickleItemExporterTest::test_fields_to_export tests/test_exporters.py::PickleItemExporterTest::test_nonstring_types_item tests/test_exporters.py::PickleItemExporterTest::test_serialize_field tests/test_exporters.py::PickleItemExporterDataclassTest::test_export_dict_item tests/test_exporters.py::PickleItemExporterDataclassTest::test_export_item tests/test_exporters.py::PickleItemExporterDataclassTest::test_export_multiple_items tests/test_exporters.py::PickleItemExporterDataclassTest::test_field_custom_serializer tests/test_exporters.py::PickleItemExporterDataclassTest::test_fields_to_export tests/test_exporters.py::PickleItemExporterDataclassTest::test_nonstring_types_item tests/test_exporters.py::PickleItemExporterDataclassTest::test_serialize_field tests/test_exporters.py::MarshalItemExporterTest::test_export_dict_item tests/test_exporters.py::MarshalItemExporterTest::test_export_item tests/test_exporters.py::MarshalItemExporterTest::test_field_custom_serializer tests/test_exporters.py::MarshalItemExporterTest::test_fields_to_export tests/test_exporters.py::MarshalItemExporterTest::test_nonstring_types_item tests/test_exporters.py::MarshalItemExporterTest::test_serialize_field tests/test_exporters.py::MarshalItemExporterDataclassTest::test_export_dict_item tests/test_exporters.py::MarshalItemExporterDataclassTest::test_export_item tests/test_exporters.py::MarshalItemExporterDataclassTest::test_field_custom_serializer tests/test_exporters.py::MarshalItemExporterDataclassTest::test_fields_to_export tests/test_exporters.py::MarshalItemExporterDataclassTest::test_nonstring_types_item tests/test_exporters.py::MarshalItemExporterDataclassTest::test_serialize_field tests/test_exporters.py::CsvItemExporterTest::test_export_dict_item tests/test_exporters.py::CsvItemExporterTest::test_export_item tests/test_exporters.py::CsvItemExporterTest::test_field_custom_serializer tests/test_exporters.py::CsvItemExporterTest::test_fields_to_export tests/test_exporters.py::CsvItemExporterTest::test_header_export_all tests/test_exporters.py::CsvItemExporterTest::test_header_export_all_dict tests/test_exporters.py::CsvItemExporterTest::test_header_export_single_field tests/test_exporters.py::CsvItemExporterTest::test_header_export_two_items tests/test_exporters.py::CsvItemExporterTest::test_header_no_header_line tests/test_exporters.py::CsvItemExporterTest::test_join_multivalue tests/test_exporters.py::CsvItemExporterTest::test_join_multivalue_not_strings tests/test_exporters.py::CsvItemExporterTest::test_nonstring_types_item tests/test_exporters.py::CsvItemExporterTest::test_serialize_field tests/test_exporters.py::CsvItemExporterDataclassTest::test_export_dict_item tests/test_exporters.py::CsvItemExporterDataclassTest::test_field_custom_serializer tests/test_exporters.py::CsvItemExporterDataclassTest::test_fields_to_export tests/test_exporters.py::CsvItemExporterDataclassTest::test_header_export_all tests/test_exporters.py::CsvItemExporterDataclassTest::test_header_export_all_dict tests/test_exporters.py::CsvItemExporterDataclassTest::test_header_export_single_field tests/test_exporters.py::CsvItemExporterDataclassTest::test_header_no_header_line tests/test_exporters.py::CsvItemExporterDataclassTest::test_join_multivalue tests/test_exporters.py::CsvItemExporterDataclassTest::test_join_multivalue_not_strings tests/test_exporters.py::CsvItemExporterDataclassTest::test_nonstring_types_item tests/test_exporters.py::CsvItemExporterDataclassTest::test_serialize_field tests/test_exporters.py::XmlItemExporterTest::test_export_dict_item tests/test_exporters.py::XmlItemExporterTest::test_export_item tests/test_exporters.py::XmlItemExporterTest::test_field_custom_serializer tests/test_exporters.py::XmlItemExporterTest::test_fields_to_export tests/test_exporters.py::XmlItemExporterTest::test_multivalued_fields tests/test_exporters.py::XmlItemExporterTest::test_nested_item tests/test_exporters.py::XmlItemExporterTest::test_nested_list_item tests/test_exporters.py::XmlItemExporterTest::test_nonstring_types_item tests/test_exporters.py::XmlItemExporterTest::test_serialize_field tests/test_exporters.py::XmlItemExporterDataclassTest::test_export_dict_item tests/test_exporters.py::XmlItemExporterDataclassTest::test_export_item tests/test_exporters.py::XmlItemExporterDataclassTest::test_field_custom_serializer tests/test_exporters.py::XmlItemExporterDataclassTest::test_fields_to_export tests/test_exporters.py::XmlItemExporterDataclassTest::test_multivalued_fields tests/test_exporters.py::XmlItemExporterDataclassTest::test_nested_item tests/test_exporters.py::XmlItemExporterDataclassTest::test_nested_list_item tests/test_exporters.py::XmlItemExporterDataclassTest::test_nonstring_types_item tests/test_exporters.py::XmlItemExporterDataclassTest::test_serialize_field tests/test_exporters.py::JsonLinesItemExporterTest::test_export_dict_item tests/test_exporters.py::JsonLinesItemExporterTest::test_export_item tests/test_exporters.py::JsonLinesItemExporterTest::test_extra_keywords tests/test_exporters.py::JsonLinesItemExporterTest::test_field_custom_serializer tests/test_exporters.py::JsonLinesItemExporterTest::test_fields_to_export tests/test_exporters.py::JsonLinesItemExporterTest::test_nested_item tests/test_exporters.py::JsonLinesItemExporterTest::test_nonstring_types_item tests/test_exporters.py::JsonLinesItemExporterTest::test_serialize_field tests/test_exporters.py::JsonLinesItemExporterDataclassTest::test_export_dict_item tests/test_exporters.py::JsonLinesItemExporterDataclassTest::test_export_item tests/test_exporters.py::JsonLinesItemExporterDataclassTest::test_extra_keywords tests/test_exporters.py::JsonLinesItemExporterDataclassTest::test_field_custom_serializer tests/test_exporters.py::JsonLinesItemExporterDataclassTest::test_fields_to_export tests/test_exporters.py::JsonLinesItemExporterDataclassTest::test_nested_item tests/test_exporters.py::JsonLinesItemExporterDataclassTest::test_nonstring_types_item tests/test_exporters.py::JsonLinesItemExporterDataclassTest::test_serialize_field tests/test_exporters.py::JsonItemExporterTest::test_export_dict_item tests/test_exporters.py::JsonItemExporterTest::test_export_item tests/test_exporters.py::JsonItemExporterTest::test_extra_keywords tests/test_exporters.py::JsonItemExporterTest::test_field_custom_serializer tests/test_exporters.py::JsonItemExporterTest::test_fields_to_export tests/test_exporters.py::JsonItemExporterTest::test_nested_dict_item tests/test_exporters.py::JsonItemExporterTest::test_nested_item tests/test_exporters.py::JsonItemExporterTest::test_nonstring_types_item tests/test_exporters.py::JsonItemExporterTest::test_serialize_field tests/test_exporters.py::JsonItemExporterTest::test_two_dict_items tests/test_exporters.py::JsonItemExporterTest::test_two_items tests/test_exporters.py::JsonItemExporterDataclassTest::test_export_dict_item tests/test_exporters.py::JsonItemExporterDataclassTest::test_export_item tests/test_exporters.py::JsonItemExporterDataclassTest::test_extra_keywords tests/test_exporters.py::JsonItemExporterDataclassTest::test_field_custom_serializer tests/test_exporters.py::JsonItemExporterDataclassTest::test_fields_to_export tests/test_exporters.py::JsonItemExporterDataclassTest::test_nested_dict_item tests/test_exporters.py::JsonItemExporterDataclassTest::test_nested_item tests/test_exporters.py::JsonItemExporterDataclassTest::test_nonstring_types_item tests/test_exporters.py::JsonItemExporterDataclassTest::test_serialize_field tests/test_exporters.py::JsonItemExporterDataclassTest::test_two_dict_items tests/test_exporters.py::JsonItemExporterDataclassTest::test_two_items tests/test_exporters.py::CustomExporterItemTest::test_exporter_custom_serializer tests/test_exporters.py::CustomExporterDataclassTest::test_exporter_custom_serializer
scrapy/exporters.py setup.cfg
scrapy/exporters.py setup.cfg