Skip to content

Commit

Permalink
Upgrade to python3.11 (#16)
Browse files Browse the repository at this point in the history
* Update requirements versions

* remove stale circle ci conf

* Update Makefile

* Remove flexisettings

* Add prefix to settings

* Update typing

* remove mypy_extensions
  • Loading branch information
eclectic-boy authored Mar 30, 2023
1 parent d0ca815 commit f48d422
Show file tree
Hide file tree
Showing 18 changed files with 124 additions and 241 deletions.
60 changes: 0 additions & 60 deletions .circleci/config.yml

This file was deleted.

5 changes: 1 addition & 4 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,11 @@ tag:
git push --tags

mypy:
mypy --py2 --ignore-missing-imports popget
mypy --ignore-missing-imports popget

pytest:
py.test -v -s tests/

pytest-pdb:
py.test -v -s --ipdb tests/

test:
$(MAKE) mypy
$(MAKE) pytest
Expand Down
39 changes: 6 additions & 33 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -31,21 +31,14 @@ as your existing Django ``settings.py``.
To bootstrap this, there are a couple of env vars to control how config
is loaded:

- ``POPGET_APP_CONFIG``
should be an import path to a python module, for example:
``POPGET_APP_CONFIG=django.conf.settings``
- ``POPGET_CONFIG_NAMESPACE``
Sets the prefix used for loading further config values from env and
config file. Defaults to ``POPGET``.

See source of ``popget/conf/defaults.py`` for more details.
See source of ``popget/conf/settings.py`` for more details.

Some useful config keys (all of which are prefixed with
``POPGET_`` by default):

- ``<namespace>_CLIENT_DEFAULT_USER_AGENT`` when making requests, popget will use this
- ``POPGET_CLIENT_DEFAULT_USER_AGENT`` when making requests, popget will use this
string as the user agent.
- ``<namespace>_CLIENT_TIMEOUT`` if ``None`` then no timeout, otherwise this timeout
- ``POPGET_CLIENT_TIMEOUT`` if ``None`` then no timeout, otherwise this timeout
(in seconds) will be applied to all requests. Requests which timeout will
return a 504 response, which will be raised as an ``HTTPError``.

Expand Down Expand Up @@ -313,32 +306,12 @@ Compatibility
This project is tested against:

=========== ===
Python 2.7 *
Python 3.7 *
Python 3.11 *
=========== ===

Running the tests
-----------------

CircleCI
~~~~~~~~

| The easiest way to test the full version matrix is to install the
CircleCI command line app:
| https://circleci.com/docs/2.0/local-jobs/
| (requires Docker)
The cli does not support 'workflows' at the moment so you have to run
the two Python version jobs separately:

.. code:: bash
circleci build --job python-2.7
.. code:: bash
circleci build --job python-3.7
py.test (single python version)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Expand All @@ -349,6 +322,6 @@ Decide which Python version you want to test and create a virtualenv:

.. code:: bash
pyenv virtualenv 3.7.4 popget
python -m virtualenv .venv -p python3.11
pip install -r requirements-test.txt
py.test -v -s --ipdb tests/
py.test -v -s tests/
2 changes: 1 addition & 1 deletion popget/__about__.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__version__ = '1.8.3'
__version__ = '2.0.0'
4 changes: 2 additions & 2 deletions popget/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from popget.client import APIClient # noqa
from popget.endpoint import ( # noqa
from popget.client import APIClient
from popget.endpoint import (
Arg,
BodyType,
DeleteEndpoint,
Expand Down
70 changes: 28 additions & 42 deletions popget/client.py
Original file line number Diff line number Diff line change
@@ -1,31 +1,18 @@
from functools import partial
from six import add_metaclass
from typing import Any, Callable, Dict, Optional, Set, Tuple, Type, TypeVar, Union # noqa
from typing import Any, Callable, Type

from mypy_extensions import Arg, DefaultArg, KwArg
import requests
from requests.exceptions import Timeout

from popget.conf import settings
from popget.endpoint import APIEndpoint, BodyType, BODY_CONTENT_TYPES, NO_DEFAULT
from popget.errors import MissingRequiredArg
from popget.extratypes import ResponseTypes # noqa
from popget.extratypes import ResponseTypes
from popget.utils import get_base_attr, update_nested


ClientMethod = Callable[
[
Arg(Type['APIClient'], 'cls'),
DefaultArg(Optional[Dict[Any, Any]], '_request_kwargs'),
DefaultArg(Optional[requests.Session], '_session'),
KwArg(object),
],
Union[ResponseTypes, object]
]


def method_factory(endpoint, client_method_name):
# type: (APIEndpoint, str) -> ClientMethod
def method_factory(endpoint: APIEndpoint, client_method_name: str):
"""
Kwargs:
endpoint: the endpoint to generate a callable method for
Expand All @@ -36,8 +23,9 @@ def method_factory(endpoint, client_method_name):
In turn the method returns response content, either string or
deserialized JSON data.
"""
def _prepare_request(base_url, _request_kwargs=None, **call_kwargs):
# type: (str, Optional[Dict], **Any) -> Tuple[str, Dict[str, Dict]]
def _prepare_request(
base_url: str, _request_kwargs: dict | None = None, **call_kwargs
) -> tuple[str, dict[str, dict]]:
"""
Kwargs:
base_url: base url of API
Expand Down Expand Up @@ -100,12 +88,12 @@ def _prepare_request(base_url, _request_kwargs=None, **call_kwargs):

return url, request_kwargs

def client_method(cls, # type: Type[APIClient]
_request_kwargs=None, # type: Optional[Dict]
_session=None, # type: requests.Session
**call_kwargs
):
# type: (...) -> Union[ResponseTypes, object]
def client_method(
cls,
_request_kwargs: dict | None = None,
_session: requests.Session | None = None,
**call_kwargs
) -> ResponseTypes | object:
"""
Returns:
Response... for non-async clients this will be response content,
Expand All @@ -126,17 +114,16 @@ def client_method(cls, # type: Type[APIClient]

class ConfigClass(object):

base_url = None # type: str
session_cls = None # type: Type[requests.Session]
_session = None # type: requests.Session
base_url: str
session_cls: Type[requests.Session]
_session: requests.Session | None = None

def __init__(self, config):
self.base_url = getattr(config, 'base_url', '')
self.session_cls = getattr(config, 'session_cls', requests.Session)

@property
def session(self):
# type: () -> requests.Session
def session(self) -> requests.Session:
if not self._session:
session = self.session_cls()
session.headers['User-Agent'] = settings.CLIENT_DEFAULT_USER_AGENT
Expand Down Expand Up @@ -179,8 +166,9 @@ class Config:
config_class = ConfigClass

@staticmethod
def add_methods_for_endpoint(methods, name, endpoint, config):
# type: (Dict[str, classmethod], str, APIEndpoint, Any) -> None
def add_methods_for_endpoint(
methods: dict[str, classmethod], name: str, endpoint: APIEndpoint, config: Any
) -> None:
methods[name] = classmethod(method_factory(endpoint, '_make_request'))

def __new__(cls, name, bases, attrs):
Expand All @@ -198,8 +186,7 @@ def __new__(cls, name, bases, attrs):
return type.__new__(cls, name, bases, attrs)


def get_response_body(response):
# type: (requests.Response) -> ResponseTypes
def get_response_body(response: requests.Response) -> ResponseTypes:
"""
Kwargs:
response: from requests lib
Expand Down Expand Up @@ -231,12 +218,12 @@ def get_response_body(response):
@add_metaclass(APIClientMetaclass)
class APIClient(object):

_config = None # type: ConfigClass
_config: ConfigClass

@staticmethod
def _request_kwargs(method, url, args, kwargs):
# type: (str, str, Tuple[Any, ...], Dict[str, Any]) -> None

def _request_kwargs(
method: str, url: str, args: tuple[Any, ...], kwargs: dict[str, Any]
) -> None:
if settings.CLIENT_DISABLE_VERIFY_SSL:
kwargs['verify'] = False

Expand All @@ -245,9 +232,7 @@ def _request_kwargs(method, url, args, kwargs):
kwargs['timeout'] = settings.CLIENT_TIMEOUT

@staticmethod
def handle(call, request_url):
# type: (Callable[[], requests.Response], str) -> ResponseTypes

def handle(call: Callable[[], requests.Response], request_url: str) -> ResponseTypes:
try:
res = call()
except Timeout as e:
Expand All @@ -262,8 +247,9 @@ def handle(call, request_url):
return get_response_body(res)

@classmethod
def _make_request(cls, method, url, session=None, *args, **kwargs):
# type: (str, str, Optional[requests.Session], *Any, **Any) -> ResponseTypes
def _make_request(
cls, method: str, url: str, session: requests.Session | None = None, *args, **kwargs
) -> ResponseTypes:
"""
Don't call this directly. Instead, add APIEndpoint instances to your
APIClient sub-class definition. Accessor methods will be generated by
Expand Down
4 changes: 0 additions & 4 deletions popget/conf/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +0,0 @@
from flexisettings import Settings


settings = Settings('POPGET', 'popget.conf.defaults')
18 changes: 0 additions & 18 deletions popget/conf/defaults.py

This file was deleted.

14 changes: 14 additions & 0 deletions popget/conf/settings.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
from popget.__about__ import __version__

try:
from django.conf import settings
except ImportError:
settings = None

CLIENT_DEFAULT_USER_AGENT: str = getattr(
settings, 'POPGET_CLIENT_DEFAULT_USER_AGENT', 'popget/{}'.format(__version__)
)

CLIENT_TIMEOUT: float = getattr(settings, 'POPGET_CLIENT_TIMEOUT', 3.0)

CLIENT_DISABLE_VERIFY_SSL: bool = getattr(settings, 'POPGET_CLIENT_DISABLE_VERIFY_SSL', False)
Loading

0 comments on commit f48d422

Please sign in to comment.