Uplink 📡¶
A Declarative HTTP Client for Python. Inspired by Retrofit.
Note
Uplink is currently in initial development. Until the official
release (v1.0.0
), the public API should be considered provisional.
Although we don’t expect any considerable changes to the API at this point,
please avoid using the code in production, for now.
However, while Uplink is under construction, we invite eager users to install early and provide open feedback, which can be as simple as opening a GitHub issue when you notice a missing feature, latent defect, documentation oversight, etc.
Moreover, for those interested in contributing, checkout the Contribution Guide on GitHub!
Uplink turns your HTTP API into a Python class.
from uplink import Consumer, get, headers, Path, Query
class GitHub(Consumer):
@get("users/{user}/repos")
def list_repos(self, user: Path, sort_by: Query("sort")):
"""Get user's public repositories."""
Build an instance to interact with the webservice.
github = GitHub(base_url="https://api.github.com/")
Then, executing an HTTP request is as simply as invoking a method.
repos = github.list_repos("octocat", sort_by="created")
The returned object is a friendly requests.Response
:
print(repos.json())
# Output: [{'id': 64778136, 'name': 'linguist', ...
For sending non-blocking requests, Uplink comes with support for
aiohttp
and twisted
(example).
Use decorators and function annotations to describe the HTTP request:
- URL parameter replacement and query parameter support
- Convert responses into Python objects (e.g., using
marshmallow
) - JSON, URL-encoded, and multipart request body and file upload
- Inject functions as middleware to define custom response and error handling
The User Manual¶
Follow this guide to get up and running with Uplink.
Installation¶
Download the Source Code¶
Uplink’s source code is in a public repository hosted on GitHub.
As an alternative to installing with pip, you could clone the repository,
$ git clone https://github.com/prkumar/uplink.git
then, install; e.g., with setup.py
:
$ cd uplink
$ python setup.py install
Extras¶
These are optional integrations and features that extend the library’s core functionality and typically require an additional dependency.
When installing Uplink with pip
, you can specify any of the following
extras, to add their respective dependencies to your installation:
Extra | Description |
---|---|
aiohttp |
Enables uplink.AiohttpClient ,
for sending non-blocking requests
and receiving awaitable responses. |
marshmallow |
Enables uplink.MarshmallowConverter ,
for converting JSON responses directly into Python objects
using marshmallow.Schema . |
twisted |
Enables uplink.TwistedClient ,
for sending non-blocking requests and receiving
Deferred responses. |
To download all available features, run
$ pip install -U uplink[aiohttp, marshmallow, twisted]
Introduction¶
Uplink delivers reusable and self-sufficient objects for accessing HTTP webservices, with minimal code and user pain. Simply define your consumers using decorators and function annotations, and we’ll handle the rest for you… pun intended, obviously 😎
Static Request Handling¶
Method decorators describe request properties that are relevant to all invocations of a consumer method.
For instance, consider the following GitHub API consumer:
class GitHub(uplink.Consumer):
@uplink.timeout(60)
@uplink.get("/repositories")
def get_repos(self):
"""Dump every public repository."""
Annotated with timeout
, the method get_repos()
will build
HTTP requests that wait an allotted number of seconds – 60, in this case –
for the server to respond before giving up.
As method annotations are simply decorators, you can stack one on top of another for chaining:
class GitHub(uplink.Consumer):
@uplink.headers({"Accept": "application/vnd.github.v3.full+json"})
@uplink.timeout(60)
@uplink.get("/repositories")
def get_repos(self):
"""Dump every public repository."""
Dynamic Request Handling¶
For programming in general, function parameters drive a function’s
dynamic behavior; a function’s output depends normally on its inputs.
With uplink
, function arguments parametrize an HTTP request,
and you indicate the dynamic parts of the request by appropriately
annotating those arguments.
To illustrate, for the method get_user()
in the following
snippet, we have flagged the argument username
as a URI
placeholder replacement using the Path
annotation:
class GitHub(uplink.Consumer):
@uplink.get("users/{username}")
def get_user(self, username: uplink.Path("username")): pass
Invoking this method on a consumer instance, like so:
github.get_user(username="prkumar")
Builds an HTTP request that has a URL ending with users/prkumar
.
Note
As you probably took away from the above example: when parsing the
method’s signature for argument annotations, uplink
skips
the instance reference argument, which is the leading method
parameter and usually named self
.
Quickstart¶
Decorators and function annotations indicate how a request will be handled.
Request Method¶
Uplink offers decorators that turn any method into a request definition. These
decorators provide the request method and relative URL of the intended
request: get
, post
,
put
, patch
and delete
.
The relative URL of the resource is specified in the decorator.
@get("users/list")
You can also specify query parameters in the URL.
@get("users/list?sort=desc")
Moreover, request methods must be bound to a Consumer
subclass.
class MyApi(Consumer):
@get("users/list")
def list_users(self):
"""List all users."""
URL Manipulation¶
A request URL can be updated dynamically using URI template parameters. A simple URI parameter is an
alphanumeric string surrounded by {
and }
.
To match the parameter with a method argument, either match the argument’s name with the alphanumeric string, like so
@get("group/{id}/users")
def group_list(self, id): pass
or use the Path
annotation.
@get("group/{id}/users")
def group_list(self, group_id: Path("id")): pass
Query
parameters can also be added.
@get("group/{id}/users")
def group_list(self, group_id: Path("id"), sort: Query): pass
For complex query parameter combinations, a mapping can be used:
@get("group/{id}/users")
def group_list(self, group_id: Path("id"), options: QueryMap): pass
Request Body¶
An argument’s value can be specified for use as an HTTP request body with the
Body
annotation:
@post("users/new")
def create_user(self, user: Body): pass
This annotation works well with the keyword arguments parameter (denoted by the ** prefix):
@post("users/new")
def create_user(self, **user_info: Body): pass
Form Encoded, Multipart, and JSON¶
Methods can also be declared to send form-encoded, multipart, and JSON data.
Form-encoded data is sent when form_url_encoded
decorates
the method. Each key-value pair is annotated with a Field
annotation:
@form_url_encoded
@post("user/edit")
def update_user(self, first_name: Field, last_name: Field): pass
Multipart requests are used when multipart
decorates the
method. Parts are declared using the Part
annotation:
@multipart
@put("user/photo")
def update_user(self, photo: Part, description: Part): pass
JSON data is sent when json
decorates the method. The
Body
annotation declares the JSON payload:
@uplink.json
@uplink.patch("/user")
def update_user(self, **user_info: uplink.Body):
"""Update an authenticated user."""
Header Manipulation¶
You can set static headers for a method using the headers
decorator.
@headers({
"Accept": "application/vnd.github.v3.full+json",
"User-Agent": "Uplink-Sample-App"
})
@get("users/{username}")
def get_user(self, username): pass
headers
can be used as a class decorator for headers that
need to be added to every request:
@headers({
"Accept": "application/vnd.github.v3.full+json",
"User-Agent": "Uplink-Sample-App"
})
class GitHub(Consumer):
...
A request header can be updated dynamically using the Header
function parameter annotation:
@get("user")
def get_user(self, authorization: Header):
"""Get an authenticated user."""
Synchronous vs. Asynchronous¶
By default, Uplink uses the Requests library to make requests. However, the
client
parameter of the Consumer
constructor offers a
way to swap out Requests with another HTTP client:
github = GitHub(BASE_URL, client=...)
Notably, Requests blocks while waiting for a response from a server.
For non-blocking requests, Uplink comes with optional support for
asyncio
and twisted
. Checkout this
example on GitHub
for more.
Deserializing the Response¶
The converter
parameter of the Consumer
constructor
accepts an adapter class that handles deserialization of HTTP response objects.
github = GitHub(BASE_URL, converter=...)
For instance, the MarshmallowConverter
adapter turns JSON
HTTP responses into Python objects using the marshmallow.Schema
object. Checkout this example on GitHub for more.
Custom Response and Error Handling¶
New in version 0.4.0.
To register a custom response or error handler, decorate a function with
the response_handler
or error_handler
decorator.
For instance, the function accept_json()
defined below is a response
handler that outputs the JSON body of a given response:
@uplink.response_handler
def accept_json(response):
return response.json()
Now, accept_json()
can be used as a decorator to inject its custom
response handling into any request method:
@accept_json
@get("/todo/{id}")
def get_todo(self, id):
"""Get the todo with the given id."""
To apply the function’s handling onto all request methods of a
Consumer
subclass, we can simply use the registered handler
as a class decorator:
@accept_json
class TodoApp(uplink.Consumer):
...
Similarly, functions decorated with error_handler
are registered
error handlers. When applied to a request method, these handlers are
invoked when the underlying HTTP client fails to execute a request:
@error_handler
def raise_api_error(exc_type, exc_val, exc_tb):
# wrap client error with custom API error
...
Notably, handlers can be stacked on top of one another to chain their behavior:
@raise_api_error
@accept_json
class TodoApp(uplink.Consumer):
...
Annotating __init__()
Arguments¶
New in version 0.4.0.
Function annotations like Query
and Header
can
be used with constructor arguments of a Consumer
subclass.
When a new consumer instance is created, the value of these arguments are
applied to all requests made through that instance.
For example, the following consumer accepts the API access token as the
constructor argument access_token
:
class GitHub(uplink.Consumer):
def __init__(self, access_token: uplink.Query):
...
@uplink.post("/user")
def update_user(self, **info: Body):
"""Update the authenticated user"""
Now, all requests made from an instance of this consumer class will be authenticated with the access token passed in at initialization:
github = TodoApp("my-github-access-token")
# This request will include the above access token as a query parameter.
github.update_user(bio="Beam me up, Scotty!")
_inject()
Request Properties¶
New in version 0.4.0.
As an alternative to Annotating __init__() Arguments, you can achieve
a similar behavior with more control by using the
Consumer._inject()
method. With this method, you can calculate
request properties within plain old python methods.
class TodoApp(uplink.Consumer):
def __init__(self, username, password)
# Create an access token
api_key = create_api_key(username, password)
# Inject it.
self._inject(uplink.Query("api_key").with_value(api_key))
Similar to the annotation style, request properties added with
_inject()
method are applied to all requests made
through the consumer instance.
Authentication¶
This section covers how to do authentication with Uplink.
Basic Authentication¶
In v0.4, we added the auth
parameter to the
uplink.Consumer
constructor.
Now it’s simple to construct a consumer that uses HTTP Basic Authentication with all requests:
github = GitHub(BASE_URL, auth=("user", "pass"))
Other Authentication¶
Often, APIs accept credentials as header values or query parameters. Your request method can handle these types of authentication by simply accepting the user’s credentials as an argument:
@post("/user")
def update_user(self, access_token: Query, **info: Body):
"""Update the user associated to the given access token."""
If more than one request requires authentication, you can make the token an argument of your consumer constructor (see Annotating __init__() Arguments):
class GitHub(Consumer):
def __init__(self, base_url, access_token: Query)
...
Using Auth Support for Requests and aiohttp¶
As we work towards Uplink’s v1.0 release, improving built-in support for other types of authentication is a continuing goal.
With that said, if Uplink currently doesn’t offer a solution for you authentication needs, you can always leverage the available auth support for the underlying HTTP client.
For instance, requests
offers out-of-the-box support for
making requests with HTTP Digest Authentication, which you can leverage
like so:
from requests.auth import HTTPDigestAuth
client = uplink.RequestsClient(cred=HTTPDigestAuth("user", "pass"))
api = MyApi(BASE_URL, client=client)
You can also use other third-party libraries that extend auth support for the underlying client. For instance, you can use requests-oauthlib for doing OAuth with Requests:
from requests_oauthlib import OAuth2Session
session = OAuth2Session(...)
api = MyApi(BASE_URL, client=session)
Tips & Tricks¶
Here are a few ways to simplify consumer definitions.
Decorating All Request Methods in a Class¶
To apply a decorator across all methods in a class, you can simply decorate the class rather than each method individually:
@uplink.timeout(60)
class GitHub(uplink.Consumer):
@uplink.get("/repositories")
def get_repos(self):
"""Dump every public repository."""
@uplink.get("/organizations")
def get_organizations(self):
"""List all organizations."""
Hence, the consumer defined above is equivalent to the following, slightly more verbose definition:
class GitHub(uplink.Consumer):
@uplink.timeout(60)
@uplink.get("/repositories")
def get_repos(self):
"""Dump every public repository."""
@uplink.timeout(60)
@uplink.get("/organizations")
def get_organizations(self):
"""List all organizations."""
Adopting the Argument’s Name¶
Several function argument annotations accept a name
parameter
on construction. For instance, the Path
annotation
uses the name
parameter to associate the function argument to
a URI path parameter:
class GitHub(uplink.Consumer):
@uplink.get("users/{username}")
def get_user(self, username: uplink.Path("username")): pass
For such annotations, you can omit the name
parameter to have the
annotation adopt the name of its corresponding method argument.
For instance, from the previous example, we can omit naming the
Path
annotation since the corresponding argument’s
name, username
, matches the intended URI path parameter.
class GitHub(uplink.Consumer):
@uplink.get("users/{username}")
def get_user(self, username: uplink.Path): pass
Some annotations that support this behavior include:
Path
, uplink.Field
, Part
Header
, and uplink.Query
.
Annotating Your Arguments For Python 2.7¶
There are several ways to annotate arguments. Most examples in this
documentation use function annotations, but this approach is unavailable
for Python 2.7 users. Instead, you should utilize the method annotation
args
.
Using uplink.args
¶
The recommended approach for Python 2.7 users involves using the method
annotation args
, arranging annotations in the same
order as their corresponding function arguments (again, ignore
self
):
class GitHub(uplink.Consumer):
@uplink.args(uplink.Url, uplink.Path)
@uplink.get
def get_commit(self, commits_url, sha): pass
The Public API¶
This guide details the classes and methods in Uplink’s public API.
Decorators¶
The method decorators detailed in this section describe request properties that are relevant to all invocations of a consumer method.
headers¶
-
class
uplink.
headers
(arg, **kwargs)¶ A decorator that adds static headers for API calls.
@headers({"User-Agent": "Uplink-Sample-App}) @get("/user") def get_user(self): """Get the current user"""
When used as a class decorator,
headers
applies to all consumer methods bound to the class:@headers({"Accept": "application/vnd.github.v3.full+json") class GitHub(Consumer): ...
headers
takes the same arguments asdict
.Parameters: - *arg – A dict containing header values.
- **kwargs – More header values.
json¶
-
class
uplink.
json
¶ Use as a decorator to make JSON requests.
You should annotate a method argument with uplink.Body which indicates that the argument’s value should become the request’s body.
uplink.Body
has to be either a dict or a subclass of py:class:collections.Mapping.Example
@json @patch(/user") def update_user(self, **info: Body): """Update the current user."""
form_url_encoded¶
-
class
uplink.
form_url_encoded
¶ URL-encodes the request body.
Used on POST/PUT/PATCH request. It url-encodes the body of the message and sets the appropriate
Content-Type
header. Further, each field argument should be annotated withuplink.Field
.Example
@form_url_encoded @post("/users/edit") def update_user(self, first_name: Field, last_name: Field): """Update the current user."""
multipart¶
timeout¶
-
class
uplink.
timeout
(seconds)¶ Time to wait for a server response before giving up.
When used on other decorators it specifies how long (in secs) a decorator should wait before giving up.
Example
@timeout(60) @get("/user/posts") def get_posts(self): """Fetch all posts for the current users."""
When used as a class decorator,
timeout
applies to all consumer methods bound to the class.Parameters: seconds (int) – An integer used to indicate how long should the request wait.
args¶
-
class
uplink.
args
(*annotations, **more_annotations)¶ Annotate method arguments for Python 2.7 compatibility.
Arrange annotations in the same order as their corresponding function arguments.
Example
@args(Path, Query) @get("/users/{username}) def get_user(self, username, visibility): """Get a specific user."""
Use keyword args to target specific method parameters.
Example
@args(visibility=Query) @get("/users/{username}) def get_user(self, username, visibility): """Get a specific user."""
Parameters: - *annotations – Any number of annotations.
- **more_annotations – More annotations, targeting specific method arguments.
response_handler¶
-
class
uplink.
response_handler
(handler)¶ A decorator for creating custom response handlers.
To register a function as a custom response handler, decorate the function with this class. The decorated function should accept a single positional argument, an HTTP response object:
Example
@response_handler def raise_for_status(response): response.raise_for_status() return response
Then, to apply custom response handling to a request method, simply decorate the method with the registered response handler:
Example
@raise_for_status @get("/user/posts") def get_posts(self): """Fetch all posts for the current users."""
To apply custom response handling on all request methods of a
uplink.Consumer
subclass, simply decorate the class with the registered response handler:Example
@raise_for_status class GitHub(Consumer): ...
New in version 0.4.0.
error_handler¶
-
class
uplink.
error_handler
(exception_handler)¶ A decorator for creating custom error handlers.
To register a function as a custom error handler, decorate the function with this class. The decorated function should accept three positional arguments: (1) the type of the exception, (2) the exception instance raised, and (3) a traceback instance.
Example
@error_handler def raise_api_error(exc_type, exc_val, exc_tb): # wrap client error with custom API error ...
Then, to apply custom error handling to a request method, simply decorate the method with the registered error handler:
Example
@raise_api_error @get("/user/posts") def get_posts(self): """Fetch all posts for the current users."""
To apply custom error handling on all request methods of a
uplink.Consumer
subclass, simply decorate the class with the registered error handler:Example
@raise_api_error class GitHub(Consumer): ...
New in version 0.4.0.
Note
Error handlers can not completely suppress exceptions. The original exception is thrown if the error handler doesn’t throw anything.
Function Annotations¶
For programming in general, function parameters drive a function’s
dynamic behavior; a function’s output depends normally on its inputs.
With uplink
, function arguments parametrize an HTTP request,
and you indicate the dynamic parts of the request by appropriately
annotating those arguments with the classes detailed in this section.
Path¶
-
class
uplink.
Path
(name=None, type=None)¶ Substitution of a path variable in a URI template.
URI template parameters are enclosed in braces (e.g.,
{name}
). To map an argument to a declared URI parameter, use thePath
annotation:class TodoService(object): @get("/todos{/id}") def get_todo(self, todo_id: Path("id")): pass
Then, invoking
get_todo
with a consumer instance:todo_service.get_todo(100)
creates an HTTP request with a URL ending in
/todos/100
.Note
Any unannotated function argument that shares a name with a URL path parameter is implicitly annotated with this class at runtime.
For example, we could simplify the method from the previous example by matching the path variable and method argument names:
@get("/todos{/id}") def get_todo(self, id): pass
Query¶
-
class
uplink.
Query
(name=None, encoded=False, type=None)¶ Set a dynamic query parameter.
This annotation turns argument values into URL query parameters. You can include it as function argument annotation, in the format:
<query argument>: uplink.Query
.If the API endpoint you are trying to query uses
q
as a query parameter, you can addq: uplink.Query
to the consumer method to set theq
search term at runtime.Example
@get("/search/commits") def search(self, search_term: Query("q")): '''Search all commits with the given search term.'''
To specify whether or not the query parameter is already URL encoded, use the optional
encoded
argument:@get("/search/commits") def search(self, search_term: Query("q", encoded=True)): """Search all commits with the given search term."""
Parameters: encoded ( bool
, optional) – Specifies whether the parametername
and value are already URL encoded.
QueryMap¶
-
class
uplink.
QueryMap
(encoded=False, type=None)¶ A mapping of query arguments.
If the API you are using accepts multiple query arguments, you can include them all in your function method by using the format:
<query argument>: uplink.QueryMap
Example
@get("/search/users") def search(self, **params: QueryMap): """Search all users."""
Parameters: encoded ( bool
, optional) – Specifies whether the parametername
and value are already URL encoded.
Header¶
-
class
uplink.
Header
(name=None, type=None)¶ Pass a header as a method argument at runtime.
While
uplink.headers
attaches static headers that define all requests sent from a consumer method, this class turns a method argument into a dynamic header value.Example
@get("/user") def (self, session_id: Header("Authorization")): """Get the authenticated user"""
HeaderMap¶
Field¶
-
class
uplink.
Field
(name=None, type=None)¶ Defines a form field to the request body.
Use together with the decorator
uplink.form_url_encoded
and annotate each argument accepting a form field withuplink.Field
.- Example::
@form_url_encoded @post("/users/edit") def update_user(self, first_name: Field, last_name: Field): """Update the current user."""
FieldMap¶
-
class
uplink.
FieldMap
(type=None)¶ Defines a mapping of form fields to the request body.
Use together with the decorator
uplink.form_url_encoded
and annotate each argument accepting a form field withuplink.FieldMap
.Example
@form_url_encoded @post("/user/edit") def create_post(self, **user_info: FieldMap): """Update the current user."""
Part¶
-
class
uplink.
Part
(name=None, type=None)¶ Marks an argument as a form part.
Use together with the decorator
uplink.multipart
and annotate each form part withuplink.Part
.Example
@multipart @put(/user/photo") def update_user(self, photo: Part, description: Part): """Upload a user profile photo."""
PartMap¶
-
class
uplink.
PartMap
(type=None)¶ A mapping of form field parts.
Use together with the decorator
uplink.multipart
and annotate each part of form parts withuplink.PartMap
Example
@multipart @put(/user/photo") def update_user(self, photo: Part, description: Part): """Upload a user profile photo."""
Body¶
-
class
uplink.
Body
(type=None)¶ Set the request body at runtime.
Use together with the decorator
uplink.json
. The method argument value will become the request’s body when annotated withuplink.Body
.Example
@json @patch(/user") def update_user(self, **info: Body): """Update the current user."""
Url¶
-
class
uplink.
Url
¶ Sets a dynamic URL.
Provides the URL at runtime as a method argument. Drop the decorator parameter path from
uplink.get
and annotate the corresponding argument withuplink.Url
Example
@get def get(self, endpoint: Url): """Execute a GET requests against the given endpoint"""
HTTP Clients¶
The client
parameter of the Consumer
constructor offers a way
to swap out Requests with another HTTP client, including those listed here:
github = GitHub(BASE_URL, client=...)
Requests¶
-
class
uplink.
RequestsClient
(session=None, **kwargs)¶ A
requests
client that returnsrequests.Response
responses.Parameters: session ( requests.Session
, optional) – The session that should handle sending requests. If this argument is omitted or set toNone
, a new session will be created.
Aiohttp¶
-
class
uplink.
AiohttpClient
(session=None, **kwargs)¶ An
aiohttp
client that creates awaitable responses.Note
This client is an optional feature and requires the
aiohttp
package. For example, here’s how to install this extra using pip:$ pip install uplink[aiohttp]
Parameters: session ( aiohttp.ClientSession
, optional) – The session that should handle sending requests. If this argument is omitted or set toNone
, a new session will be created.
Twisted¶
-
class
uplink.
TwistedClient
(session=None)¶ Client that returns
twisted.internet.defer.Deferred
responses.Note
This client is an optional feature and requires the
twisted
package. For example, here’s how to install this extra using pip:$ pip install uplink[twisted]
Parameters: session ( requests.Session
, optional) – The session that should handle sending requests. If this argument is omitted or set toNone
, a new session will be created.
Converters¶
The converter
parameter of the uplink.Consumer
constructor
accepts an adapter class that handles deserialization of HTTP response objects:
github = GitHub(BASE_URL, converter=...)
Marshmallow¶
-
class
uplink.
MarshmallowConverter
¶ A converter that serializes and deserializes values using
marshmallow
schemas.To deserialize JSON responses into Python objects with this converter, define a
marshmallow.Schema
subclass and set it as the return annotation of a consumer method:@get("/users") def get_users(self, username) -> UserSchema(): '''Fetch a single user'''
Also, when instantiating a consumer, be sure to set this class as a converter for the instance:
github = GitHub(BASE_URL, converter=MarshmallowConverter())
Note
This converter is an optional feature and requires the
marshmallow
package. For example, here’s how to install this feature using pip:$ pip install uplink[marshmallow]
Changelog¶
All notable changes to this project will be documented in this file.
The format is based on Keep a Changelog, and this project adheres to the Semantic Versioning scheme.
0.4.1 - 2018-3-10¶
Fixed¶
- Enforce method-level decorators override class-level decorators when they conflict.
0.4.0 - 2018-2-10¶
Added¶
- Support for Basic Authentication.
- The
response_handler
decorator for defining custom response handlers. - The
error_handler
decorator for defining custom error handlers. - The
inject
decorator for injecting other kinds of middleware. - The
Consumer._inject
method for adding middleware to a consumer instance. - Support for annotating constructor arguments of a
Consumer
subclass with built-in function annotations likeQuery
andHeader
.
0.3.0 - 2018-1-09¶
Added¶
- HTTP HEAD request decorator by @brandonio21.
- Support for returning deserialized response objects using
marshmallow
schemas. - Constructor parameter for
Query
andQueryMap
to support already encoded URL parameters. - Support for using
requests.Session
andaiohttp.ClientSession
instances with theclient
parameter of theConsumer
constructor.
Changed¶
aiohttp
andtwisted
are now optional dependencies/extras.
Fixed¶
- Fix for calling a request method with
super
, by @brandonio21. - Fix issue where method decorators would incorrectly decorate inherited request methods.
0.2.0 - 2017-11-03¶
Added¶
- The class
uplink.Consumer
by @itstehkman. Consumer classes should inherit this base. class, and creating consumer instances happens through instantiation. - Support for
asyncio
for Python 3.4 and above. - Support for
twisted
for all supported Python versions.
Changed¶
- BREAKING: Invoking a consumer method now builds and executes the request,
removing the extra step of calling the
execute
method.
Deprecated¶
- Building consumer instances with
uplink.build
. Instead, Consumer classes should inherituplink.Consumer
.
Fixed¶
- Header link for version 0.1.1 in changelog.
0.1.1 - 2017-10-21¶
Added¶
- Contribution guide,
CONTRIBUTING.rst
. - “Contributing” Section in README.rst that links to contribution guide.
AUTHORS.rst
file for listing project contributors.- Adopt Contributor Covenant Code of Conduct.
Changed¶
- Replaced tentative contributing instructions in preview notice on documentation homepage with link to contribution guide.
0.1.0 - 2017-10-19¶
Added¶
- Python ports for almost all method and argument annotations in Retrofit.
- Adherence to the variation of the semantic versioning scheme outlined in the official Python package distribution tutorial.
- MIT License
- Documentation with introduction, instructions for installing, and quick getting started guide covering the builder and all method and argument annotations.
- README that contains GitHub API v3 example, installation instructions with
pip
, and link to online documentation.