{"id":13792483,"url":"https://github.com/scrapy/itemadapter","last_synced_at":"2025-05-16T02:09:32.985Z","repository":{"id":43083009,"uuid":"256881218","full_name":"scrapy/itemadapter","owner":"scrapy","description":"Common interface for data container classes","archived":false,"fork":false,"pushed_at":"2025-03-24T09:15:28.000Z","size":276,"stargazers_count":67,"open_issues_count":7,"forks_count":13,"subscribers_count":8,"default_branch":"master","last_synced_at":"2025-04-01T11:05:53.662Z","etag":null,"topics":["hacktoberfest","metadata","python","python-attrs","python-dataclasses","python3","scrapy"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-3-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/scrapy.png","metadata":{"files":{"readme":"README.md","changelog":"Changelog.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-04-19T00:28:33.000Z","updated_at":"2025-03-24T09:15:33.000Z","dependencies_parsed_at":"2023-02-16T10:40:23.516Z","dependency_job_id":"40be2da5-03e5-4d49-a321-54d1063eca1b","html_url":"https://github.com/scrapy/itemadapter","commit_stats":{"total_commits":161,"total_committers":9,"mean_commits":17.88888888888889,"dds":"0.31677018633540377","last_synced_commit":"e0c3f835394daec74b552a06d920ec0e2b701532"},"previous_names":[],"tags_count":19,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/scrapy%2Fitemadapter","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/scrapy%2Fitemadapter/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/scrapy%2Fitemadapter/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/scrapy%2Fitemadapter/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/scrapy","download_url":"https://codeload.github.com/scrapy/itemadapter/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247847609,"owners_count":21006099,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["hacktoberfest","metadata","python","python-attrs","python-dataclasses","python3","scrapy"],"created_at":"2024-08-03T22:01:12.708Z","updated_at":"2025-04-08T13:05:58.436Z","avatar_url":"https://github.com/scrapy.png","language":"Python","readme":"# itemadapter\n[![version](https://img.shields.io/pypi/v/itemadapter.svg)](https://pypi.python.org/pypi/itemadapter)\n[![pyversions](https://img.shields.io/pypi/pyversions/itemadapter.svg)](https://pypi.python.org/pypi/itemadapter)\n[![actions](https://github.com/scrapy/itemadapter/workflows/Tests/badge.svg)](https://github.com/scrapy/itemadapter/actions)\n[![codecov](https://codecov.io/gh/scrapy/itemadapter/branch/master/graph/badge.svg)](https://codecov.io/gh/scrapy/itemadapter)\n\n\nThe `ItemAdapter` class is a wrapper for data container objects, providing a\ncommon interface to handle objects of different types in an uniform manner,\nregardless of their underlying implementation.\n\nCurrently supported types are:\n\n* [`scrapy.item.Item`](https://docs.scrapy.org/en/latest/topics/items.html#scrapy.item.Item)\n* [`dict`](https://docs.python.org/3/library/stdtypes.html#dict)\n* [`dataclass`](https://docs.python.org/3/library/dataclasses.html)-based classes\n* [`attrs`](https://www.attrs.org)-based classes\n* [`pydantic`](https://pydantic-docs.helpmanual.io/)-based classes\n\nAdditionally, interaction with arbitrary types is supported, by implementing\na pre-defined interface (see [extending `itemadapter`](#extending-itemadapter)).\n\n---\n\n## Requirements\n\n* Python 3.9+, either the CPython implementation (default) or the PyPy\n  implementation\n* [`scrapy`](https://scrapy.org/) 2.2+: optional, needed to interact with\n  `scrapy` items\n* [`attrs`](https://pypi.org/project/attrs/) 18.1.0+: optional, needed to\n  interact with `attrs`-based items\n* [`pydantic`](https://pypi.org/project/pydantic/) 1.8+: optional, needed to\n  interact with `pydantic`-based items\n\n---\n\n## Installation\n\n`itemadapter` is available on [`PyPI`](https://pypi.python.org/pypi/itemadapter), it can be installed with `pip`:\n\n```\npip install itemadapter\n```\n\nFor `attrs`, `pydantic` and `scrapy` support, install the corresponding extra\nto ensure that a supported version of the corresponding dependencies is\ninstalled. For example:\n\n```\npip install itemadapter[scrapy]\n```\n\nMind that you can install multiple extras as needed. For example:\n\n```\npip install itemadapter[attrs,pydantic,scrapy]\n```\n\n---\n\n## License\n\n`itemadapter` is distributed under a [BSD-3](https://opensource.org/licenses/BSD-3-Clause) license.\n\n---\n\n## Basic usage\n\nThe following is a simple example using a `dataclass` object.\nConsider the following type definition:\n\n```python\n\u003e\u003e\u003e from dataclasses import dataclass\n\u003e\u003e\u003e from itemadapter import ItemAdapter\n\u003e\u003e\u003e @dataclass\n... class InventoryItem:\n...     name: str\n...     price: float\n...     stock: int\n\u003e\u003e\u003e\n```\n\nAn `ItemAdapter` object can be treated much like a dictionary:\n\n```python\n\u003e\u003e\u003e obj = InventoryItem(name='foo', price=20.5, stock=10)\n\u003e\u003e\u003e ItemAdapter.is_item(obj)\nTrue\n\u003e\u003e\u003e adapter = ItemAdapter(obj)\n\u003e\u003e\u003e len(adapter)\n3\n\u003e\u003e\u003e adapter[\"name\"]\n'foo'\n\u003e\u003e\u003e adapter.get(\"price\")\n20.5\n\u003e\u003e\u003e\n```\n\nThe wrapped object is modified in-place:\n```python\n\u003e\u003e\u003e adapter[\"name\"] = \"bar\"\n\u003e\u003e\u003e adapter.update({\"price\": 12.7, \"stock\": 9})\n\u003e\u003e\u003e adapter.item\nInventoryItem(name='bar', price=12.7, stock=9)\n\u003e\u003e\u003e adapter.item is obj\nTrue\n\u003e\u003e\u003e\n```\n\n### Converting to dict\n\nThe `ItemAdapter` class provides the `asdict` method, which converts\nnested items recursively. Consider the following example:\n\n```python\n\u003e\u003e\u003e from dataclasses import dataclass\n\u003e\u003e\u003e from itemadapter import ItemAdapter\n\u003e\u003e\u003e @dataclass\n... class Price:\n...     value: int\n...     currency: str\n\u003e\u003e\u003e @dataclass\n... class Product:\n...     name: str\n...     price: Price\n\u003e\u003e\u003e\n```\n\n```python\n\u003e\u003e\u003e item = Product(\"Stuff\", Price(42, \"UYU\"))\n\u003e\u003e\u003e adapter = ItemAdapter(item)\n\u003e\u003e\u003e adapter.asdict()\n{'name': 'Stuff', 'price': {'value': 42, 'currency': 'UYU'}}\n\u003e\u003e\u003e\n```\n\nNote that just passing an adapter object to the `dict` built-in also works,\nbut it doesn't traverse the object recursively converting nested items:\n\n```python\n\u003e\u003e\u003e dict(adapter)\n{'name': 'Stuff', 'price': Price(value=42, currency='UYU')}\n\u003e\u003e\u003e\n```\n\n---\n\n## API reference\n\n### Built-in adapters\n\nThe following adapters are included by default:\n\n* `itemadapter.adapter.ScrapyItemAdapter`: handles `Scrapy` items\n* `itemadapter.adapter.DictAdapter`: handles `Python` dictionaries\n* `itemadapter.adapter.DataclassAdapter`: handles `dataclass` objects\n* `itemadapter.adapter.AttrsAdapter`: handles `attrs` objects\n* `itemadapter.adapter.PydanticAdapter`: handles `pydantic` objects\n\n### class `itemadapter.adapter.ItemAdapter(item: Any)`\n\nThis is the main entrypoint for the package. Tipically, user code\nwraps an item using this class, and proceeds to handle it with the provided interface.\n`ItemAdapter` implements the\n[`MutableMapping`](https://docs.python.org/3/library/collections.abc.html#collections.abc.MutableMapping)\ninterface, providing a `dict`-like API to manipulate data for the object it wraps\n(which is modified in-place).\n\n**Attributes**\n\n#### class attribute `ADAPTER_CLASSES: Iterable`\n\nStores the currently registered adapter classes.\n\nThe order in which the adapters are registered is important. When an `ItemAdapter` object is\ncreated for a specific item, the registered adapters are traversed in order and the first\nadapter class to return `True` for the `is_item` class method is used for all subsequent\noperations. The default order is the one defined in the\n[built-in adapters](#built-in-adapters) section.\n\nThe default implementation uses a\n[`collections.deque`](https://docs.python.org/3/library/collections.html#collections.deque)\nto support efficient addition/deletion of adapters classes to both ends, but if you are\nderiving a subclass (see the section on [extending itemadapter](#extending-itemadapter)\nfor additional information), any other iterable (e.g. `list`, `tuple`) will work.\n\n**Methods**\n\n#### class method `is_item(item: Any) -\u003e bool`\n\nReturn `True` if any of the registed adapters can handle the item\n(i.e. if any of them returns `True` for its `is_item` method with\n`item` as argument), `False` otherwise.\n\n#### class method `is_item_class(item_class: type) -\u003e bool`\n\nReturn `True` if any of the registered adapters can handle the item class\n(i.e. if any of them returns `True` for its `is_item_class` method with\n`item_class` as argument), `False` otherwise.\n\n#### class method `get_field_meta_from_class(item_class: type, field_name: str) -\u003e MappingProxyType`\n\nReturn a [`types.MappingProxyType`](https://docs.python.org/3/library/types.html#types.MappingProxyType)\nobject, which is a read-only mapping with metadata about the given field. If the item class does not\nsupport field metadata, or there is no metadata for the given field, an empty object is returned.\n\nThe returned value is taken from the following sources, depending on the item type:\n\n  * [`scrapy.item.Field`](https://docs.scrapy.org/en/latest/topics/items.html#item-fields)\n    for `scrapy.item.Item`s\n  * [`dataclasses.field.metadata`](https://docs.python.org/3/library/dataclasses.html#dataclasses.field)\n    for `dataclass`-based items\n  * [`attr.Attribute.metadata`](https://www.attrs.org/en/stable/examples.html#metadata)\n    for `attrs`-based items\n  * [`pydantic.fields.FieldInfo`](https://pydantic-docs.helpmanual.io/usage/schema/#field-customisation)\n    for `pydantic`-based items\n\n#### class method `get_field_names_from_class(item_class: type) -\u003e Optional[list[str]]`\n\nReturn a list with the names of all the fields defined for the item class.\nIf an item class doesn't support defining fields upfront, None is returned.\n\n#### `get_field_meta(field_name: str) -\u003e MappingProxyType`\n\nReturn metadata for the given field, if available. Unless overriden in a custom adapter class, by default\nthis method calls the adapter's `get_field_meta_from_class` method, passing the wrapped item's class.\n\n#### `field_names() -\u003e collections.abc.KeysView`\n\nReturn a [keys view](https://docs.python.org/3/library/collections.abc.html#collections.abc.KeysView)\nwith the names of all the defined fields for the item.\n\n#### `asdict() -\u003e dict`\n\nReturn a `dict` object with the contents of the adapter. This works slightly different than\ncalling `dict(adapter)`, because it's applied recursively to nested items (if there are any).\n\n\n### function `itemadapter.utils.is_item(obj: Any) -\u003e bool`\n\nReturn `True` if the given object belongs to (at least) one of the supported types,\n`False` otherwise. This is an alias, using the `itemadapter.adapter.ItemAdapter.is_item`\nclass method is encouraged for better performance.\n\n\n### function `itemadapter.utils.get_field_meta_from_class(item_class: type, field_name: str) -\u003e types.MappingProxyType`\n\nAlias for `itemadapter.adapter.ItemAdapter.get_field_meta_from_class`\n\n---\n\n## Metadata support\n\n`scrapy.item.Item`, `dataclass`, `attrs`, and `pydantic` objects allow the definition of\narbitrary field metadata. This can be accessed through a\n[`MappingProxyType`](https://docs.python.org/3/library/types.html#types.MappingProxyType)\nobject, which can be retrieved from an item instance with\n`itemadapter.adapter.ItemAdapter.get_field_meta`, or from an item class\nwith the `itemadapter.adapter.ItemAdapter.get_field_meta_from_class`\nmethod (or its alias `itemadapter.utils.get_field_meta_from_class`).\nThe source of the data depends on the underlying type (see the docs for\n`ItemAdapter.get_field_meta_from_class`).\n\n#### `scrapy.item.Item` objects\n\n```python\n\u003e\u003e\u003e from scrapy.item import Item, Field\n\u003e\u003e\u003e from itemadapter import ItemAdapter\n\u003e\u003e\u003e class InventoryItem(Item):\n...     name = Field(serializer=str)\n...     value = Field(serializer=int, limit=100)\n...\n\u003e\u003e\u003e adapter = ItemAdapter(InventoryItem(name=\"foo\", value=10))\n\u003e\u003e\u003e adapter.get_field_meta(\"name\")\nmappingproxy({'serializer': \u003cclass 'str'\u003e})\n\u003e\u003e\u003e adapter.get_field_meta(\"value\")\nmappingproxy({'serializer': \u003cclass 'int'\u003e, 'limit': 100})\n\u003e\u003e\u003e\n```\n\n#### `dataclass` objects\n\n```python\n\u003e\u003e\u003e from dataclasses import dataclass, field\n\u003e\u003e\u003e @dataclass\n... class InventoryItem:\n...     name: str = field(metadata={\"serializer\": str})\n...     value: int = field(metadata={\"serializer\": int, \"limit\": 100})\n...\n\u003e\u003e\u003e adapter = ItemAdapter(InventoryItem(name=\"foo\", value=10))\n\u003e\u003e\u003e adapter.get_field_meta(\"name\")\nmappingproxy({'serializer': \u003cclass 'str'\u003e})\n\u003e\u003e\u003e adapter.get_field_meta(\"value\")\nmappingproxy({'serializer': \u003cclass 'int'\u003e, 'limit': 100})\n\u003e\u003e\u003e\n```\n\n#### `attrs` objects\n\n```python\n\u003e\u003e\u003e import attr\n\u003e\u003e\u003e @attr.s\n... class InventoryItem:\n...     name = attr.ib(metadata={\"serializer\": str})\n...     value = attr.ib(metadata={\"serializer\": int, \"limit\": 100})\n...\n\u003e\u003e\u003e adapter = ItemAdapter(InventoryItem(name=\"foo\", value=10))\n\u003e\u003e\u003e adapter.get_field_meta(\"name\")\nmappingproxy({'serializer': \u003cclass 'str'\u003e})\n\u003e\u003e\u003e adapter.get_field_meta(\"value\")\nmappingproxy({'serializer': \u003cclass 'int'\u003e, 'limit': 100})\n\u003e\u003e\u003e\n```\n\n#### `pydantic` objects\n\n```python\n\u003e\u003e\u003e from pydantic import BaseModel, Field\n\u003e\u003e\u003e class InventoryItem(BaseModel):\n...     name: str = Field(serializer=str)\n...     value: int = Field(serializer=int, limit=100)\n...\n\u003e\u003e\u003e adapter = ItemAdapter(InventoryItem(name=\"foo\", value=10))\n\u003e\u003e\u003e adapter.get_field_meta(\"name\")\nmappingproxy({'default': PydanticUndefined, 'json_schema_extra': {'serializer': \u003cclass 'str'\u003e}, 'repr': True})\n\u003e\u003e\u003e adapter.get_field_meta(\"value\")\nmappingproxy({'default': PydanticUndefined, 'json_schema_extra': {'serializer': \u003cclass 'int'\u003e, 'limit': 100}, 'repr': True})\n\u003e\u003e\u003e\n```\n\n---\n\n## Extending `itemadapter`\n\nThis package allows to handle arbitrary item classes, by implementing an adapter interface:\n\n_class `itemadapter.adapter.AdapterInterface(item: Any)`_\n\nAbstract Base Class for adapters. An adapter that handles a specific type of item must\ninherit from this class and implement the abstract methods defined on it. `AdapterInterface`\ninherits from [`collections.abc.MutableMapping`](https://docs.python.org/3/library/collections.abc.html#collections.abc.MutableMapping),\nso all methods from the `MutableMapping` interface must be implemented as well.\n\n* _class method `is_item_class(cls, item_class: type) -\u003e bool`_\n\n    Return `True` if the adapter can handle the given item class, `False` otherwise. Abstract (mandatory).\n\n* _class method `is_item(cls, item: Any) -\u003e bool`_\n\n    Return `True` if the adapter can handle the given item, `False` otherwise.\n    The default implementation calls `cls.is_item_class(item.__class__)`.\n\n* _class method `get_field_meta_from_class(cls, item_class: type) -\u003e bool`_\n\n    Return metadata for the given item class and field name, if available.\n    By default, this method returns an empty `MappingProxyType` object. Please supply your\n    own method definition if you want to handle field metadata based on custom logic.\n    See the [section on metadata support](#metadata-support) for additional information.\n\n* _method `get_field_meta(self, field_name: str) -\u003e types.MappingProxyType`_\n\n    Return metadata for the given field name, if available. It's usually not necessary to\n    override this method, since the `itemadapter.adapter.AdapterInterface` base class\n    provides a default implementation that calls `ItemAdapter.get_field_meta_from_class`\n    with the wrapped item's class as argument.\n    See the [section on metadata support](#metadata-support) for additional information.\n\n* _method `field_names(self) -\u003e collections.abc.KeysView`_:\n\n    Return a [dynamic view](https://docs.python.org/3/library/collections.abc.html#collections.abc.KeysView)\n    of the item's field names. By default, this method returns the result of calling `keys()` on\n    the current adapter, i.e., its return value depends on the implementation of the methods from the\n    `MutableMapping` interface (more specifically, it depends on the return value of `__iter__`).\n\n    You might want to override this method if you want a way to get all fields for an item, whether or not\n    they are populated. For instance, Scrapy uses this method to define column names when exporting items to CSV.\n\n### Registering an adapter\n\nAdd your custom adapter class to the\n`itemadapter.adapter.ItemAdapter.ADAPTER_CLASSES` class attribute in order to\nhandle custom item classes.\n\n**Example**\n```\npip install zyte-common-items\n```\n```python\n\u003e\u003e\u003e from itemadapter.adapter import ItemAdapter\n\u003e\u003e\u003e from zyte_common_items import Item, ZyteItemAdapter\n\u003e\u003e\u003e\n\u003e\u003e\u003e ItemAdapter.ADAPTER_CLASSES.appendleft(ZyteItemAdapter)\n\u003e\u003e\u003e item = Item()\n\u003e\u003e\u003e adapter = ItemAdapter(item)\n\u003e\u003e\u003e adapter\n\u003cItemAdapter for Item()\u003e\n\u003e\u003e\u003e\n```\n\n### Multiple adapter classes\n\nIf you need to have different handlers and/or priorities for different cases\nyou can subclass the `ItemAdapter` class and set the `ADAPTER_CLASSES`\nattribute as needed:\n\n\n**Example**\n```python\n\u003e\u003e\u003e from itemadapter.adapter import (\n...     ItemAdapter,\n...     AttrsAdapter,\n...     DataclassAdapter,\n...     DictAdapter,\n...     PydanticAdapter,\n...     ScrapyItemAdapter,\n... )\n\u003e\u003e\u003e from scrapy.item import Item, Field\n\u003e\u003e\u003e\n\u003e\u003e\u003e class BuiltinTypesItemAdapter(ItemAdapter):\n...     ADAPTER_CLASSES = [DictAdapter, DataclassAdapter]\n...\n\u003e\u003e\u003e class ThirdPartyTypesItemAdapter(ItemAdapter):\n...     ADAPTER_CLASSES = [AttrsAdapter, PydanticAdapter, ScrapyItemAdapter]\n...\n\u003e\u003e\u003e class ScrapyItem(Item):\n...     foo = Field()\n...\n\u003e\u003e\u003e BuiltinTypesItemAdapter.is_item(dict())\nTrue\n\u003e\u003e\u003e ThirdPartyTypesItemAdapter.is_item(dict())\nFalse\n\u003e\u003e\u003e BuiltinTypesItemAdapter.is_item(ScrapyItem(foo=\"bar\"))\nFalse\n\u003e\u003e\u003e ThirdPartyTypesItemAdapter.is_item(ScrapyItem(foo=\"bar\"))\nTrue\n\u003e\u003e\u003e\n```\n\n---\n\n## More examples\n\n### `scrapy.item.Item` objects\n\n```python\n\u003e\u003e\u003e from scrapy.item import Item, Field\n\u003e\u003e\u003e from itemadapter import ItemAdapter\n\u003e\u003e\u003e class InventoryItem(Item):\n...     name = Field()\n...     price = Field()\n...\n\u003e\u003e\u003e item = InventoryItem(name=\"foo\", price=10)\n\u003e\u003e\u003e adapter = ItemAdapter(item)\n\u003e\u003e\u003e adapter.item is item\nTrue\n\u003e\u003e\u003e adapter[\"name\"]\n'foo'\n\u003e\u003e\u003e adapter[\"name\"] = \"bar\"\n\u003e\u003e\u003e adapter[\"price\"] = 5\n\u003e\u003e\u003e item\n{'name': 'bar', 'price': 5}\n\u003e\u003e\u003e\n```\n\n### `dict`\n\n```python\n\u003e\u003e\u003e from itemadapter import ItemAdapter\n\u003e\u003e\u003e item = dict(name=\"foo\", price=10)\n\u003e\u003e\u003e adapter = ItemAdapter(item)\n\u003e\u003e\u003e adapter.item is item\nTrue\n\u003e\u003e\u003e adapter[\"name\"]\n'foo'\n\u003e\u003e\u003e adapter[\"name\"] = \"bar\"\n\u003e\u003e\u003e adapter[\"price\"] = 5\n\u003e\u003e\u003e item\n{'name': 'bar', 'price': 5}\n\u003e\u003e\u003e\n```\n\n### `dataclass` objects\n\n```python\n\u003e\u003e\u003e from dataclasses import dataclass\n\u003e\u003e\u003e from itemadapter import ItemAdapter\n\u003e\u003e\u003e @dataclass\n... class InventoryItem:\n...     name: str\n...     price: int\n...\n\u003e\u003e\u003e item = InventoryItem(name=\"foo\", price=10)\n\u003e\u003e\u003e adapter = ItemAdapter(item)\n\u003e\u003e\u003e adapter.item is item\nTrue\n\u003e\u003e\u003e adapter[\"name\"]\n'foo'\n\u003e\u003e\u003e adapter[\"name\"] = \"bar\"\n\u003e\u003e\u003e adapter[\"price\"] = 5\n\u003e\u003e\u003e item\nInventoryItem(name='bar', price=5)\n\u003e\u003e\u003e\n```\n\n### `attrs` objects\n\n```python\n\u003e\u003e\u003e import attr\n\u003e\u003e\u003e from itemadapter import ItemAdapter\n\u003e\u003e\u003e @attr.s\n... class InventoryItem:\n...     name = attr.ib()\n...     price = attr.ib()\n...\n\u003e\u003e\u003e item = InventoryItem(name=\"foo\", price=10)\n\u003e\u003e\u003e adapter = ItemAdapter(item)\n\u003e\u003e\u003e adapter.item is item\nTrue\n\u003e\u003e\u003e adapter[\"name\"]\n'foo'\n\u003e\u003e\u003e adapter[\"name\"] = \"bar\"\n\u003e\u003e\u003e adapter[\"price\"] = 5\n\u003e\u003e\u003e item\nInventoryItem(name='bar', price=5)\n\u003e\u003e\u003e\n```\n\n### `pydantic` objects\n\n```python\n\u003e\u003e\u003e from pydantic import BaseModel\n\u003e\u003e\u003e from itemadapter import ItemAdapter\n\u003e\u003e\u003e class InventoryItem(BaseModel):\n...     name: str\n...     price: int\n...\n\u003e\u003e\u003e item = InventoryItem(name=\"foo\", price=10)\n\u003e\u003e\u003e adapter = ItemAdapter(item)\n\u003e\u003e\u003e adapter.item is item\nTrue\n\u003e\u003e\u003e adapter[\"name\"]\n'foo'\n\u003e\u003e\u003e adapter[\"name\"] = \"bar\"\n\u003e\u003e\u003e adapter[\"price\"] = 5\n\u003e\u003e\u003e item\nInventoryItem(name='bar', price=5)\n\u003e\u003e\u003e\n```\n\n\n## Changelog\n\nSee the [full changelog](Changelog.md)\n","funding_links":[],"categories":["Apps"],"sub_categories":["Other Useful Extensions"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fscrapy%2Fitemadapter","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fscrapy%2Fitemadapter","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fscrapy%2Fitemadapter/lists"}