{ "info": { "author": "Depop", "author_email": "dev@depop.com", "bugtrack_url": null, "classifiers": [ "Environment :: Web Environment", "Intended Audience :: Developers", "License :: OSI Approved :: Apache Software License", "Operating System :: OS Independent", "Programming Language :: Python", "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3.6" ], "description": "popget\n======\n\n|PyPI Version| |Build Status|\n\n.. |PyPI Version| image:: http://img.shields.io/pypi/v/popget.svg?style=flat\n :target: https://pypi.python.org/pypi/popget/\n :alt: Latest PyPI version\n\n.. |Build Status| image:: https://circleci.com/gh/depop/popget.svg?style=shield&circle-token=66ab09119c495365d662fe170e5efcc4467e3b37\n :alt: Build Status\n\nA simple no-bells-and-whistles REST-API client, optionally supporting async requests.\n\nWe use this for service-to-service requests in our heterogenous\nmicroservices environment.\n\nUsage\n-----\n\n.. code:: bash\n\n pip install popget\n\n\nConfiguration\n~~~~~~~~~~~~~\n\nSettings are intended to be configured primarily via a python file, such\nas your existing Django ``settings.py``.\nTo bootstrap this, there are a couple of env vars to control how config\nis loaded:\n\n- ``POPGET_APP_CONFIG``\n should be an import path to a python module, for example:\n ``POPGET_APP_CONFIG=django.conf.settings``\n- ``POPGET_CONFIG_NAMESPACE``\n Sets the prefix used for loading further config values from env and\n config file. Defaults to ``POPGET``.\n\nSee source of ``popget/conf/defaults.py`` for more details.\n\nSome useful config keys (all of which are prefixed with\n``POPGET_`` by default):\n\n- ``_CLIENT_DEFAULT_USER_AGENT`` when making requests, popget will use this\n string as the user agent.\n- ``_CLIENT_TIMEOUT`` if ``None`` then no timeout, otherwise this timeout\n (in seconds) will be applied to all requests. Requests which timeout will\n return a 504 response, which will be raised as an ``HTTPError``.\n\nAPIClient\n~~~~~~~~~\n\nYou will sub-class ``APIClient`` to make your API. You do not need to\ninstantiate the client, all methods are class-methods.\n\neg\n\n.. code:: python\n\n from popget import APIClient, Arg, GetEndpoint\n\n class ThingServiceClient(APIClient):\n\n class Config:\n base_url = 'http://things.depop.com'\n\n get_things = GetEndpoint(\n '/things/{user_id}/', # url format string\n querystring_args=(\n Arg('type', required=True), # required querystring param (validated on call)\n )\n )\n\nResults in a client method you can call like:\n\n.. code:: python\n\n data = ThingServiceClient.get_things(user_id=2345, type='cat')\n\nWhich will perform a request like:\n\n.. code:: bash\n\n GET http://things.depop.com/things/2345/?type=cat\n\nIf response was ``\"Content-Type: application/json\"`` then ``data`` is\nalready deserialized.\n\nUnder Python 3 there is a further distinction between ``str`` and ``bytes``.\nIf the Content-Type header contains ``text/`` then the returned value\nwill be encoded to ``str`` (by underlying ``python-requests`` lib).\nOther content types will return ``bytes``.\n\nWe use ``raise_for_status`` so anything >= 400 will raise a ``requests.HTTPError``.\n\nAPIEndpoint\n~~~~~~~~~~~\n\n``APIEndpoint`` is the base class for endpoint methods. ``GetEndpoint``,\n``PostEndpoint``, ``PutEndpoint``, ``PatchEndpoint`` and ``DeleteEndpoint``\nare provided for convenience, allowing to omit the method arg.\n\nParams from url path (format string), querystring and request headers\n(format string of value portion) will be extracted and made available\nas kwargs on the resulting callable method on your client class.\n\nThis means arg names must be unique across all three sources of args.\nThis is feasible because path and header args can be freely chosen when\nimplementing the client (they are just format string identifiers rather\nthan part of the REST API itself like querystring args are).\n\ne.g.\n\n.. code:: python\n\n from popget import APIClient, Arg, GetEndpoint\n\n class ThingServiceClient(APIClient):\n\n class Config:\n base_url = 'http://things.depop.com'\n\n get_things = GetEndpoint(\n '/things/{user_id}/', # url (format string)\n querystring_args=(\n Arg('type', required=True),\n Arg('offset_id'),\n Arg('limit', default=25),\n ),\n request_headers={ # added to all requests\n 'Authorization': 'Bearer {access_token}' # (format string)\n }\n )\n\nThis will give you a client with a ``get_things`` method you can call like:\n\n.. code:: python\n\n response_data = ThingServiceClient.get_things(\n user_id=123,\n type='cat',\n offset_id='65345ff34e344ab53c',\n limit=20,\n access_token='87a64c98b62d39e8625f',\n )\n\nQuerystring args can have a callable as the default value, e.g.:\n\n.. code:: python\n\n from datetime import datetime\n from popget import APIClient, Arg, GetEndpoint\n\n def now():\n return datetime.now().isoformat()\n\n class ThingServiceClient(APIClient):\n\n class Config:\n base_url = 'http://things.depop.com'\n\n get_things = GetEndpoint(\n '/things/{user_id}/', # url (format string)\n querystring_args=(\n Arg('since', default=now),\n ),\n request_headers={ # added to all requests\n 'Authorization': 'Bearer {access_token}' # (format string)\n }\n )\n\n response_data = ThingServiceClient.get_things(user_id=123)\n # GET http://things.depop.com/things/123/?since=2018-02-09T13:31:10.569481\n\nYou can still pass extra args down into the ``requests`` lib on a per-call\nbasis by using ``_request_kwargs``:\n\n.. code:: python\n\n response_data = ThingServiceClient.get_things(\n user_id=123,\n type='cat',\n offset_id='65345ff34e344ab53c',\n limit=20,\n access_token='87a64c98b62d39e8625f',\n _request_kwargs={\n 'headers': {\n 'X-Depop-WTF': 'something something'\n }\n },\n )\n\nAnd for calls with a request body:\n\n.. code:: python\n\n from popget import APIClient, PostEndpoint, BodyType\n\n class ThingServiceClient(APIClient):\n\n class Config:\n base_url = 'http://things.depop.com'\n\n new_thing = PostEndpoint(\n '/things/',\n body_required=True,\n body_type=BodyType.FORM_ENCODED, # or BodyType.JSON - sets content-type header\n request_headers={\n 'Authorization': 'Bearer {access_token}',\n }\n )\n\n response_data = ThingServiceClient.new_thing(\n access_token='87a64c98b62d39e8625f',\n body={\n 'type': 'dog',\n 'name': 'fido',\n }\n )\n\nYou can also pass a custom ``requests.Session`` instance on a per-request basis using the ``_session`` kwarg:\n\n.. code:: python\n\n from django.conf import settings\n from requests_oauthlib import OAuth1Session\n\n from myproject.twitter.client import TwitterClient\n\n def tweet_from(user, message, **extra):\n oauth_session = OAuth1Session(\n settings.TWITTER_CONSUMER_KEY,\n client_secret=settings.TWITTER_CONSUMER_SECRET,\n resource_owner_key=user.tw_access_token,\n resource_owner_secret=user.tw_access_token_secret,\n )\n body = {\n 'status': message,\n }\n body.update(extra)\n return TwitterClient.update_status(body=body, _session=oauth_session)\n\n\nAsynchronous\n~~~~~~~~~~~~\n\nOptional support for asynchronous requests is provided, via a\n`requests-futures `_ backend.\n\n``pip install popget[threadpool]``\n\nAn async variant of the ``APIClient`` is provided which will have both async and blocking\nversions of all endpoint methods.\n\n.. code:: python\n\n from popget import Arg, GetEndpoint\n from popget.async.threadpool import APIClient\n import requests\n\n class ThingServiceClient(APIClient):\n\n class Config:\n base_url = 'http://things.depop.com'\n\n get_things = GetEndpoint(\n '/things/{user_id}/', # url format string\n querystring_args=(\n Arg('type', required=True), # required querystring param (validated on call)\n ),\n )\n\n # blocking:\n data = ThingServiceClient.get_things(user_id=2345, type='cat')\n\n # async:\n future = ThingServiceClient.async_get_things(user_id=2345, type='cat')\n # response is parsed and may raise, as for blocking requests\n try:\n data = future.result()\n except requests.exceptions.HTTPError as e:\n print(repr(e))\n\nThe async endpoint methods will return a standard ``concurrent.futures.Future`` object.\n\nSee `Python docs `_.\n\nYou can customise the name of the generated async endpoint methods:\n\n.. code:: python\n\n class ThingServiceClient(APIClient):\n\n class Config:\n base_url = 'http://things.depop.com'\n async_method_template = '{}__async'\n\n get_things = GetEndpoint(\n '/things/{user_id}/', # url format string\n querystring_args=(\n Arg('type', required=True), # required querystring param (validated on call)\n ),\n )\n\n future = ThingServiceClient.get_things__async(user_id=2345, type='cat')\n\n\nCompatibility\n-------------\n\nThis project is tested against:\n\n=========== ===\nPython 2.7 * \nPython 3.7 * \n=========== ===\n\nRunning the tests\n-----------------\n\nCircleCI\n~~~~~~~~\n\n| The easiest way to test the full version matrix is to install the\n CircleCI command line app:\n| https://circleci.com/docs/2.0/local-jobs/\n| (requires Docker)\n\nThe cli does not support 'workflows' at the moment so you have to run\nthe two Python version jobs separately:\n\n.. code:: bash\n\n circleci build --job python-2.7\n\n.. code:: bash\n\n circleci build --job python-3.7\n\npy.test (single python version)\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nIt's also possible to run the tests locally, allowing for debugging of\nerrors that occur.\n\nDecide which Python version you want to test and create a virtualenv:\n\n.. code:: bash\n\n pyenv virtualenv 3.7.4 popget\n pip install -r requirements-test.txt\n py.test -v -s --ipdb tests/", "description_content_type": "", "docs_url": null, "download_url": "", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://github.com/depop/popget", "keywords": "", "license": "Apache 2.0", "maintainer": "", "maintainer_email": "", "name": "popget", "package_url": "https://pypi.org/project/popget/", "platform": "", "project_url": "https://pypi.org/project/popget/", "project_urls": { "Homepage": "https://github.com/depop/popget" }, "release_url": "https://pypi.org/project/popget/1.8.0/", "requires_dist": null, "requires_python": "", "summary": "Simple REST-API client for Python.", "version": "1.8.0" }, "last_serial": 5539594, "releases": { "1.0.0": [ { "comment_text": "", "digests": { "md5": "068357e2bc2b52edab8c9c3cec1cdce4", "sha256": "9aced050b829c21a190dfb3b3864212ba165476b4f48ef01988d5f356b4d6781" }, "downloads": -1, "filename": "popget-1.0.0.tar.gz", "has_sig": false, "md5_digest": "068357e2bc2b52edab8c9c3cec1cdce4", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 8174, "upload_time": "2017-11-13T18:32:07", "url": "https://files.pythonhosted.org/packages/e6/c1/e9dda838e49b1ab9a1bf1c816334f18f99e5b55f218c3d6b1903f399eace/popget-1.0.0.tar.gz" } ], "1.1.0": [ { "comment_text": "", "digests": { "md5": "9c1bf153790d9b44e591276aa56c5f52", "sha256": "34a9c7ee16a21ec374e5c4c56ed4656f533161ff335e6719898c418a342911be" }, "downloads": -1, "filename": "popget-1.1.0.tar.gz", "has_sig": false, "md5_digest": "9c1bf153790d9b44e591276aa56c5f52", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 11936, "upload_time": "2017-11-20T17:33:40", "url": "https://files.pythonhosted.org/packages/2a/99/38fcc5a658138cf4f74b7f9df5450cb3a01922dcd990269b1c7b47524f62/popget-1.1.0.tar.gz" } ], "1.3.0": [ { "comment_text": "", "digests": { "md5": "4b072c323389c8abb3c7ea9f153bcb0f", "sha256": "bd44378ab01406a58b0bb6969c7a9a34878804b516619ad06186b9ff386fdbad" }, "downloads": -1, "filename": "popget-1.3.0.tar.gz", "has_sig": false, "md5_digest": "4b072c323389c8abb3c7ea9f153bcb0f", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 10953, "upload_time": "2018-02-07T12:26:33", "url": "https://files.pythonhosted.org/packages/45/37/b4bbeff786e9eb06236d136fe034dc0538bc2c7a4509fcb0899e83f9232f/popget-1.3.0.tar.gz" } ], "1.4.0": [ { "comment_text": "", "digests": { "md5": "2d9c3aea8e1cb14dccbeba9a7e48ec44", "sha256": "bc76360ed81ffed634745d3116dc1884aee26cfda423ef4484460e1d43cf9a59" }, "downloads": -1, "filename": "popget-1.4.0.tar.gz", "has_sig": false, "md5_digest": "2d9c3aea8e1cb14dccbeba9a7e48ec44", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 11292, "upload_time": "2018-02-08T15:38:28", "url": "https://files.pythonhosted.org/packages/b2/3a/097c5fa4789066be29bc79da53bddf1b29b8e862c257e143eca0218cb50a/popget-1.4.0.tar.gz" } ], "1.5.0": [ { "comment_text": "", "digests": { "md5": "883dd42af5d1af052e835657c69d305a", "sha256": "b4cbcb4760b2f511ac621114dbadb2d31920f88bc9cf76c12bb2a88a4a5ee5b4" }, "downloads": -1, "filename": "popget-1.5.0.tar.gz", "has_sig": false, "md5_digest": "883dd42af5d1af052e835657c69d305a", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 11486, "upload_time": "2018-02-09T14:17:58", "url": "https://files.pythonhosted.org/packages/ad/7f/67259862f6d1c934b6b09365283cde14971dda764279814197165042c67d/popget-1.5.0.tar.gz" } ], "1.5.1": [ { "comment_text": "", "digests": { "md5": "eee7fa480d85f1c613c7da57c5cabba5", "sha256": "a2eda88679b04d9aca964be0db76f7a5dded092474bc7d476d15bfc4ff5918c9" }, "downloads": -1, "filename": "popget-1.5.1.tar.gz", "has_sig": false, "md5_digest": "eee7fa480d85f1c613c7da57c5cabba5", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 11523, "upload_time": "2018-02-20T10:17:46", "url": "https://files.pythonhosted.org/packages/7d/87/845ec29cffa38ee6a5f04e81a379d6eebdf6ab292e8d93c8115b870a1cfc/popget-1.5.1.tar.gz" } ], "1.6.0": [ { "comment_text": "", "digests": { "md5": "2dfb0f60feb73cc5d3f2c5f97d8506cf", "sha256": "694829e2244906cc3887bf7cc115c3661638f0e6bb40dceccf80badf354d343a" }, "downloads": -1, "filename": "popget-1.6.0.tar.gz", "has_sig": false, "md5_digest": "2dfb0f60feb73cc5d3f2c5f97d8506cf", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 11728, "upload_time": "2018-02-20T11:25:59", "url": "https://files.pythonhosted.org/packages/a7/29/96967add22c5c5cc774519ec340106ff3352c22362b10b6b078ffd521e3b/popget-1.6.0.tar.gz" } ], "1.6.1": [ { "comment_text": "", "digests": { "md5": "063e95ae7c85e2e8c9356c079fcfc42d", "sha256": "b691a8def1c74fb6be5fc36923897c0c614d6980db1b596f57d8e8e0e7d36ca6" }, "downloads": -1, "filename": "popget-1.6.1.tar.gz", "has_sig": false, "md5_digest": "063e95ae7c85e2e8c9356c079fcfc42d", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 11730, "upload_time": "2018-03-14T12:47:01", "url": "https://files.pythonhosted.org/packages/3e/72/1bcf218ada587e57b540b2a00bdb2d76fef395ce0bfc45049cdaae47d35f/popget-1.6.1.tar.gz" } ], "1.7.0": [ { "comment_text": "", "digests": { "md5": "00415c43a95e15ac3684d5c988480d0c", "sha256": "44a6902de782a8f7430fa053583cbefd530c7afe3b6c61dbb229336fe4bda77a" }, "downloads": -1, "filename": "popget-1.7.0.tar.gz", "has_sig": false, "md5_digest": "00415c43a95e15ac3684d5c988480d0c", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 11746, "upload_time": "2019-06-19T10:55:56", "url": "https://files.pythonhosted.org/packages/4b/a5/4a595b6ed9d76a575b83459142ac1109cfd59b783237c97a2fea413ffd81/popget-1.7.0.tar.gz" } ], "1.8.0": [ { "comment_text": "", "digests": { "md5": "949c556daed6c263837c3bd75c65e593", "sha256": "38f6ab34799bea95859cb2d5cefdf688c28852650399274eb82335d50e771bb7" }, "downloads": -1, "filename": "popget-1.8.0.tar.gz", "has_sig": false, "md5_digest": "949c556daed6c263837c3bd75c65e593", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 11779, "upload_time": "2019-07-16T10:02:31", "url": "https://files.pythonhosted.org/packages/71/47/18a50efb26d4243862e7533c2e38caf04739b790aec837555ce78c0475c8/popget-1.8.0.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "949c556daed6c263837c3bd75c65e593", "sha256": "38f6ab34799bea95859cb2d5cefdf688c28852650399274eb82335d50e771bb7" }, "downloads": -1, "filename": "popget-1.8.0.tar.gz", "has_sig": false, "md5_digest": "949c556daed6c263837c3bd75c65e593", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 11779, "upload_time": "2019-07-16T10:02:31", "url": "https://files.pythonhosted.org/packages/71/47/18a50efb26d4243862e7533c2e38caf04739b790aec837555ce78c0475c8/popget-1.8.0.tar.gz" } ] }