{"id":16838831,"url":"https://github.com/alexei/python-adapters","last_synced_at":"2025-03-22T05:30:48.661Z","repository":{"id":20241791,"uuid":"87003919","full_name":"alexei/python-adapters","owner":"alexei","description":"Adapters allow converting data from one structure to another","archived":false,"fork":false,"pushed_at":"2022-06-09T09:46:48.000Z","size":43,"stargazers_count":10,"open_issues_count":14,"forks_count":2,"subscribers_count":6,"default_branch":"master","last_synced_at":"2025-03-18T08:21:41.161Z","etag":null,"topics":["adapter-pattern","python"],"latest_commit_sha":null,"homepage":"https://pypi.python.org/pypi/python-adapters","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/alexei.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2017-04-02T17:43:41.000Z","updated_at":"2023-06-13T14:29:53.000Z","dependencies_parsed_at":"2022-08-18T00:00:35.126Z","dependency_job_id":null,"html_url":"https://github.com/alexei/python-adapters","commit_stats":null,"previous_names":[],"tags_count":6,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alexei%2Fpython-adapters","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alexei%2Fpython-adapters/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alexei%2Fpython-adapters/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alexei%2Fpython-adapters/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/alexei","download_url":"https://codeload.github.com/alexei/python-adapters/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":244912800,"owners_count":20530764,"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":["adapter-pattern","python"],"created_at":"2024-10-13T12:26:39.759Z","updated_at":"2025-03-22T05:30:46.561Z","avatar_url":"https://github.com/alexei.png","language":"Python","readme":"# Adapters\n\n[![Build Status](https://travis-ci.org/alexei/python-adapters.svg?branch=master)](https://travis-ci.org/alexei/python-adapters)\n\nAdapters allow converting data from one structure to another.\n\nThe adapters work very similar to `Serializers` in Django REST framework. They are not tied with Django nor DRF in any way, instead they provide a generic way of transforming an object to another.\n\nThe are intended to be used when working with 3rd party APIs and as View-Models.\n\n## Example\n\nSuppose you're dealing with an API that returns a profile in the following format:\n\n    {\n        \"first_name\": \"Alexandra\",\n        \"last_name\": \"Johnson\",\n        \"dob\": \"2/27/1985\",\n        \"address_street\": [\"71 Boat Lane\"],\n        \"address_zip\": \"EH45 0ZQ\",\n        \"address_city\": \"Alderton\",\n        \"address_country\": \"GB\"\n    }\n\nBut your local models are a little different:\n\n    class Address(object):\n        def __init__(self, **kwargs):\n            self.line1 = kwargs.get('line1', None)\n            self.line2 = kwargs.get('line2', None)\n            self.postal_code = kwargs.get('postal_code', None)\n            self.city = kwargs.get('city', None)\n            self.region = kwargs.get('region', None)\n            self.country = kwargs.get('country', None)\n\n\n    class Profile(object):\n        def __init__(self, **kwargs):\n            self.first_name = kwargs.get('first_name', None)\n            self.last_name = kwargs.get('last_name', None)\n            self.birthday = kwargs.get('birthday', None)\n            self.address = kwargs.get('address', None)\n\nHow do you create local instances from the result returned by the API? Enter adapters:\n\n    import adapters\n\n\n    class AddressAdapter(adapters.Adapter):\n        class Meta(object):\n            model = Address\n\n        line1 = adapters.CharField(source='address_street.0')\n        line2 = adapters.CharField(source='address_street.1', default='')\n        postal_code = adapters.CharField(source='address_zip')\n        city = adapters.CharField(source='address_city')\n        region = adapters.CharField(source='address_region', default='')\n        country = adapters.CharField(source='address_country')\n\n\n    class ProfileAdapter(adapters.Adapter):\n        class Meta(object):\n            model = Profile\n\n        first_name = adapters.CharField()\n        first_name = adapters.CharField()\n        birthday = adapters.DateField(source='dob')\n        address = AddressAdapter(source='*')\n\n\n    ProfileAdapter().adapt(remote_data)\n\n\n## Declaring adapters\n\nDeclaring an adapter is as simple as inheriting from `adapters.Adapter`.\n\nThe `data` argument can be omitted and passed to the `.adapt()` method. See [Adapting data](#adapting-data) below.\n\nThe `instance` argument is optional and it allows converting to an existing instance i.e. instead of creating a new one.\n\n### Meta options\n\nThe `Meta.model` field specifies the type of the end result. Defaults to `dict` and as such the data is converted to a dictionary.\n\n### Adapting data\n\nTo convert data from one format to another, call the `Adapter.adapt()` method. It accepts an optional `data` argument which refers to the data to be converted.\n\n## Fields\n\nEach field accepts the following arguments:\n\n* `source` refers to the attribute that will be used to populate the field; the default is to use the same name as the field;\n\nThe `source` argument can use dotted notation to traverse objects e.g. `profile.birthday`.\n\nThe value `*` can be used to indicate the adapter to pass the entire object to the field.\n\n* `default` specifies the default value of the resulting field; if not set and the field is required, it will raise an error\n* `required` indicates whether the field should be required or not; default is `True`\n\nThe following field types are available:\n\n### AdapterMethodField\n\nThe field gets it's value by calling a method defined on the adapter class. It can be used to manipulate the data.\n\nThe `method_name` argument refers to the name of the method. It defaults to `get_\u003cfield_name\u003e`.\n\n### BooleanField\n\nConverts the result to a boolean value.\n\n### CharField\n\nA Unicode field.\n\n### DateField\n\nParses the value into a `datetime.date` object.\n\n### DateTimeField\n\nParses the value into a `datetime.datetime` object.\n\n### DecimalField\n\nParses the value into a `Decimal` object.\n\n### FloatField\n\nA float field.\n\n### IntField\n\nAn integer field.\n\n### TimeField\n\nParses the value into a `datetime.time` object.\n\n### VerbatimField\n\nCopy the value as is.\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Falexei%2Fpython-adapters","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Falexei%2Fpython-adapters","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Falexei%2Fpython-adapters/lists"}