# -*- coding: utf-8 -*-
from abc import ABC, abstractmethod
from typing import Any
from . import requests
[docs]class AbstractAPIPath(ABC):
"""
The syntactic sugar factory
Every time you get an attribute or an item from an instance of this
class this will be appended to its ``_path`` until you call a request
method (like get or post)
It makes it easy to call any endpoint of the api
The ``client`` given as an parameter during the creation of the
BaseAPIPath instance can be accessed as the ``_client`` attribute of
the instance.
.. warning::
You must create a child class of AbstractAPIPath to perform
requests (you have to implement the _request method)
Parameters
----------
path : str
Value of ``_path``
suffix : str
suffix to append to the url
client : .client.BasePeonyClient
client used to perform the request
"""
def __init__(self, path, suffix, client):
self._path = path
self._suffix = suffix
self.client = client
[docs] def url(self, suffix=None):
"""
Build the url using the _path attribute
Parameters
----------
suffix : str
String to be appended to the url
Returns
-------
str
Path to the endpoint
"""
return "/".join(self._path) + (suffix or self._suffix)
def __getitem__(self, key: Any) -> "AbstractAPIPath": # noqa: E501
"""
Where the magic happens
If the key is a request method (eg. get) call the _request
attribute with the method as argument
otherwise append the key to the _path attribute
>>> api = APIPath() # you would have to add more arguments
>>> api['client'] # appends 'client' to _path
Parameters
----------
key : :obj:`str`, :obj:`tuple` or :obj:`list`
Key used to access an API endpoint and appended to the
path attribute
Returns
-------
BaseAPIPath
New APIPath instance with a new ``path`` value
"""
if isinstance(key, (str, int)):
new_path = self._path + [key]
elif isinstance(key, (tuple, list)):
key = [str(i) for i in key]
new_path = self._path + key
else:
raise TypeError(
"Could not create endpoint from %s of type %s" % (key, type(key))
)
return self.__class__(path=new_path, suffix=self._suffix, client=self.client)
def __getattr__(self, key: str) -> "AbstractAPIPath": # noqa: E501
"""
Call __getitem__ when trying to get an attribute from the
instance
If your path contains an actual attribute of the instance
you should call __getitem__ instead
"""
return self[key]
@property
def get(self):
return self._request("get")
@property
def post(self):
return self._request("post")
@property
def put(self):
return self._request("put")
@property
def delete(self):
return self._request("delete")
@property
def patch(self):
return self._request("patch")
@property
def option(self):
return self._request("option")
@property
def head(self):
return self._request("head")
@abstractmethod
def _request(self, method: str) -> requests.RequestFactory:
"""
Make a request for the endpoint
Parameters
----------
method : str
method to use to make the request
"""
def __str__(self):
return repr(self)
def __repr__(self):
return "<%s %s>" % (self.__class__.__name__, self.url())
[docs]class APIPath(AbstractAPIPath):
"""
Class to make requests to a REST API
Parameters
----------
path : str
Value of ``_path``
suffix : str
suffix to append to the url
client : .client.BasePeonyClient
client used to perform the request
"""
def _request(self, method):
return requests.RequestFactory(self, method)