Skip to content

Commit

Permalink
Version 1.3.0
Browse files Browse the repository at this point in the history
- remove jsonmarshal. Users now have the option of installing package api-client-jsonmarshal which will perform the same actions. This allows usage of python versions 3.6+
- test against python3.6. And test against tenacity versions
- remove yaml response handler
  • Loading branch information
MikeWooster authored and MikeWooster committed Feb 2, 2021
1 parent ddbe361 commit fbb473b
Show file tree
Hide file tree
Showing 14 changed files with 21 additions and 367 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: [3.7, 3.8]
python-version: [3.6, 3.7, 3.8]

steps:
- uses: actions/checkout@v2
Expand All @@ -25,4 +25,4 @@ jobs:
tox -e lint
- name: Unit Tests
run: |
tox -e unittest
tox
2 changes: 1 addition & 1 deletion .github/workflows/test_and_deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ jobs:
tox -e lint
- name: Unit Tests
run: |
tox -e unittest
tox
deploy:
needs: test
Expand Down
14 changes: 0 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -362,20 +362,6 @@ client = ClientImplementation(
)
```

### `YamlResponseHandler`
Handler that parses the response data in `yaml` format and returns the
dictionary. If an error occurs trying to parse the yaml then an `UnexpectedError`
will be raised.

Example:
```python
client = ClientImplementation(
authentication_method=...,
response_handler=YamlResponseHandler,
request_formatter=...,
)
```

## Request Formatters

Request formatters provide a way in which the outgoing request data can
Expand Down
2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
1.2.2
1.3.0
8 changes: 1 addition & 7 deletions apiclient/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,7 @@
)
from apiclient.client import APIClient
from apiclient.decorates import endpoint
from apiclient.json import marshal_request, unmarshal_response
from apiclient.paginators import paginated
from apiclient.request_formatters import JsonRequestFormatter
from apiclient.response_handlers import (
JsonResponseHandler,
RequestsResponseHandler,
XmlResponseHandler,
YamlResponseHandler,
)
from apiclient.response_handlers import JsonResponseHandler, RequestsResponseHandler, XmlResponseHandler
from apiclient.retrying import retry_request
2 changes: 1 addition & 1 deletion apiclient/authentication_methods.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ def get_query_params(self):
class HeaderAuthentication(BaseAuthenticationMethod):
"""Authentication provided within the header.
Normally associated with Oauth authoriazation, in the format:
Normally associated with Oauth authorization, in the format:
"Authorization: Bearer <token>"
"""

Expand Down
41 changes: 0 additions & 41 deletions apiclient/json.py

This file was deleted.

18 changes: 0 additions & 18 deletions apiclient/response_handlers.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,10 @@
from typing import Optional
from xml.etree import ElementTree

import yaml
from requests import Response

from apiclient.exceptions import ResponseParseError
from apiclient.utils.typing import JsonType, XmlType
from apiclient.utils.warnings import deprecation_warning


class BaseResponseHandler:
Expand Down Expand Up @@ -58,19 +56,3 @@ def get_request_data(response: Response) -> Optional[XmlType]:
f"Unable to parse response data to xml. data='{response.text}'"
) from error
return xml_element


class YamlResponseHandler(BaseResponseHandler):
"""Attempt to return the decoded response as yaml."""

@staticmethod
def get_request_data(response: Response) -> JsonType:
deprecation_warning("YamlResponseHandler will be removed in version 1.3.0")

try:
response_yaml = yaml.load(response.text)
except yaml.YAMLError as error:
raise ResponseParseError(
f"Unable to parse response data to yaml. data='{response.text}'"
) from error
return response_yaml
4 changes: 2 additions & 2 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import setuptools

# Pinning tenacity as the api has changed slightly which breaks all tests.
application_dependencies = ["requests>=2.16", "pyyaml", "tenacity>=5.1.0", "jsonmarshal"]
application_dependencies = ["requests>=2.16", "tenacity>=5.1.0"]
prod_dependencies = []
test_dependencies = ["pytest", "pytest-env", "pytest-cov", "vcrpy", "requests-mock"]
lint_dependencies = ["flake8", "flake8-docstrings", "black", "isort"]
Expand All @@ -29,7 +29,7 @@
author="Mike Wooster",
author_email="",
url="https://github.com/MikeWooster/api-client",
python_requires=">=3.7",
python_requires=">=3.6",
packages=["apiclient"],
classifiers=[
"Development Status :: 5 - Production/Stable",
Expand Down
57 changes: 1 addition & 56 deletions tests/integration_tests/client.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,4 @@
from dataclasses import dataclass
from typing import List, Optional

from jsonmarshal import json_field

from apiclient import APIClient, endpoint, paginated, retry_request, unmarshal_response
from apiclient import APIClient, endpoint, paginated, retry_request


def by_query_params_callable(response, prev_params):
Expand Down Expand Up @@ -55,53 +50,3 @@ def delete_user(self, user_id):
@paginated(by_query_params=by_query_params_callable)
def list_user_accounts_paginated(self, user_id):
return self.get(Urls.accounts, params={"userId": user_id})


@dataclass
class User:
user_id: int = json_field(json="userId")
first_name: str = json_field(json="firstName")
last_name: str = json_field(json="lastName")


@dataclass
class Account:
account_name: str = json_field(json="accountName")
number: str = json_field(json="number")


@dataclass
class AccountPage:
results: List[Account] = json_field(json="results")
page: int = json_field(json="page")
next_page: Optional[int] = json_field(json="nextPage")


class ClientWithJson(Client):
@unmarshal_response(List[User])
def list_users(self):
return super().list_users()

@unmarshal_response(User)
def get_user(self, user_id: int):
return super().get_user(user_id)

@unmarshal_response(User)
def create_user(self, first_name, last_name):
return super().create_user(first_name, last_name)

@unmarshal_response(User)
def overwrite_user(self, user_id, first_name, last_name):
return super().overwrite_user(user_id, first_name, last_name)

@unmarshal_response(User)
def update_user(self, user_id, first_name=None, last_name=None):
return super().update_user(user_id, first_name, last_name)

def delete_user(self, user_id):
return super().delete_user(user_id)

@unmarshal_response(List[AccountPage])
@paginated(by_query_params=by_query_params_callable)
def list_user_accounts_paginated(self, user_id):
return self.get(Urls.accounts, params={"userId": user_id})
83 changes: 1 addition & 82 deletions tests/integration_tests/test_client_integration.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

from apiclient import JsonRequestFormatter, JsonResponseHandler, NoAuthentication
from apiclient.exceptions import ClientError, RedirectionError, ServerError, UnexpectedError
from tests.integration_tests.client import Account, AccountPage, Client, ClientWithJson, Urls, User
from tests.integration_tests.client import Client, Urls


def test_client_response(cassette):
Expand Down Expand Up @@ -85,87 +85,6 @@ def test_client_response(cassette):
assert str(exc_info.value) == "Error when contacting 'mock://testserver'"


def test_client_response_with_jsonmarshal(cassette):

client = ClientWithJson(
authentication_method=NoAuthentication(),
response_handler=JsonResponseHandler,
request_formatter=JsonRequestFormatter,
)
users = client.list_users()
assert len(users) == 3
assert users == [
User(user_id=1, first_name="Mike", last_name="Foo"),
User(user_id=2, first_name="Sarah", last_name="Bar"),
User(user_id=3, first_name="Barry", last_name="Baz"),
]
assert cassette.play_count == 1

# User 1 requested successfully on first attempt
user = client.get_user(user_id=1)
assert user == User(user_id=1, first_name="Mike", last_name="Foo")
assert cassette.play_count == 2

# User 2 failed on first attempt, succeeded on second
user = client.get_user(user_id=2)
assert user == User(user_id=2, first_name="Sarah", last_name="Bar")

assert cassette.play_count == 4

new_user = client.create_user(first_name="Lucy", last_name="Qux")
assert new_user == User(user_id=4, first_name="Lucy", last_name="Qux")

assert cassette.play_count == 5

overwritten_user = client.overwrite_user(user_id=4, first_name="Lucy", last_name="Foo")
assert overwritten_user == User(user_id=4, first_name="Lucy", last_name="Foo")
assert cassette.play_count == 6

updated_user = client.update_user(user_id=4, first_name="Lucy", last_name="Qux")
assert updated_user == User(user_id=4, first_name="Lucy", last_name="Qux")
assert cassette.play_count == 7

# DELETE cassette doesn't seem to be working correctly.
# deleted_user = client.delete_user(user_id=4)
# assert deleted_user is None
# assert cassette.play_count == 8

# paginated responds with a generator, so need to cast to list.
pages = list(client.list_user_accounts_paginated(user_id=1))
assert len(pages) == 3
assert pages == [
AccountPage(
results=[
Account(account_name="business", number="1234"),
Account(account_name="expense", number="2345"),
],
page=1,
next_page=2,
),
AccountPage(
results=[
Account(account_name="fun", number="6544"),
Account(account_name="holiday", number="9283"),
],
page=2,
next_page=3,
),
AccountPage(
results=[
Account(account_name="gifts", number="7827"),
Account(account_name="home", number="1259"),
],
page=3,
next_page=None,
),
]

# Fails to connect when connecting to non-existent url.
with pytest.raises(UnexpectedError) as exc_info:
client.get("mock://testserver")
assert str(exc_info.value) == "Error when contacting 'mock://testserver'"


@pytest.mark.parametrize(
"user_id,expected_error,expected_message",
[
Expand Down
Loading

0 comments on commit fbb473b

Please sign in to comment.