Skip to content

Commit

Permalink
Health API methods do not require OandaClient.initialize()
Browse files Browse the repository at this point in the history
  • Loading branch information
jamespeterschinner committed Dec 26, 2017
1 parent 4d32fc5 commit 10dd7da
Show file tree
Hide file tree
Showing 5 changed files with 49 additions and 32 deletions.
24 changes: 13 additions & 11 deletions async_v20/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
from .interface import *



async def sleep(s=0.0):
await asyncio.sleep(s)

Expand Down Expand Up @@ -223,6 +222,17 @@ def close(self):
# In case the client was never initialized
pass

async def initialize_session(self):
# Create http session this client will use to sent all requests
conn = aiohttp.TCPConnector(limit=self.max_simultaneous_connections)

self.session = aiohttp.ClientSession(
json_serialize=json.dumps,
headers=self.headers,
connector=conn,
read_timeout=self.rest_timeout
)

async def initialize(self, initialization_step=False):
"""Initialize client instance
Expand All @@ -249,16 +259,8 @@ async def initialize(self, initialization_step=False):
self.initializing = True # immediately set initializing to make sure
# Upcoming requests wait for this initialization to complete.

# Create http session this client will use to sent all requests
conn = aiohttp.TCPConnector(limit=self.max_simultaneous_connections)

self.session = aiohttp.ClientSession(
json_serialize=json.dumps,
headers=self.headers,
connector=conn,
read_timeout=self.rest_timeout
)

if not self.session:
await self.initialize_session()
# Get the first account listed in in accounts.
# If another is desired the account must be configured
# manually when instantiating the client
Expand Down
11 changes: 9 additions & 2 deletions async_v20/interface/decorators.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,21 +11,27 @@
from ..endpoints.annotations import SinceTransactionID


def endpoint(endpoint, rest=False, initialization_step=False):
def endpoint(endpoint, rest=False, initialization_step=False, initialize_required=True):
"""Define a method call to be exposed to the user"""


def wrapper(method):
"""Take the wrapped method and return a coroutine"""

method.endpoint = endpoint

method.initialize_required = initialize_required

sig = signature(method)

method.__doc__ = create_doc_signature(method, sig)

@wraps(method)
async def wrap(self, *args, **kwargs):
await self.initialize(initialization_step)
if initialize_required:
await self.initialize(initialization_step)
elif not self.session:
await self.initialize_session()

arguments = construct_arguments(self, sig, *args, **kwargs)

Expand Down Expand Up @@ -62,4 +68,5 @@ def wrap(self, *args, **kwargs):
wrap.shortcut = True
wrap.__signature__ = sig
wrap.__doc__ = create_doc_signature(wrap, sig)

return wrap
20 changes: 10 additions & 10 deletions async_v20/interface/health.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,61 +6,61 @@

class HealthInterface(object):

@endpoint(GETServices)
@endpoint(GETServices, initialize_required=False)
def list_services(self):
"""List all the services
"""
pass

@endpoint(GETService)
@endpoint(GETService, initialize_required=False)
def get_service(self, service_id: ServiceID):
"""Get a single service
"""
pass

@endpoint(GETServiceLists)
@endpoint(GETServiceLists, initialize_required=False)
def list_service_lists(self):
"""List all service lists
"""
pass

@endpoint(GETServiceList)
@endpoint(GETServiceList, initialize_required=False)
def get_service_list(self, service_list_id: ServiceListID):
"""Get a single service list
"""
pass

@endpoint(GETEvents)
@endpoint(GETEvents, initialize_required=False)
def list_events(self, service_id: ServiceID):
"""List all events for a service
"""
pass

@endpoint(GETCurrentEvent)
@endpoint(GETCurrentEvent, initialize_required=False)
def get_current_event(self, service_id: ServiceID):
"""Get the current event for a service
"""
pass

@endpoint(GETEvent)
@endpoint(GETEvent, initialize_required=False)
def get_event(self, service_id: ServiceID, event_sid: EventSid):
"""Get an individual event
"""
pass

@endpoint(GETStatuses)
@endpoint(GETStatuses, initialize_required=False)
def list_statuses(self):
"""List all statuses
"""
pass

@endpoint(GETStatus)
@endpoint(GETStatus, initialize_required=False)
def get_status(self, status_id: StatusID):
"""Get an individual status
"""
pass

@endpoint(GETImages)
@endpoint(GETImages, initialize_required=False)
def list_images(self):
"""List all status images
"""
Expand Down
21 changes: 13 additions & 8 deletions tests/test_client.py
Original file line number Diff line number Diff line change
@@ -1,23 +1,22 @@
import asyncio
import inspect
import os
import re
import time
from itertools import chain

import pytest
import async_v20
from aiohttp.client_exceptions import ContentTypeError

from async_v20 import AccountID
from async_v20.client import OandaClient
from async_v20.definitions.types import Account
from async_v20.endpoints.annotations import Authorization
from .fixtures import all_trades_open_closed
from .fixtures import changes_response_two
from .fixtures import server as server_module
from .fixtures.client import client
from .fixtures.static import close_all_trades_response
from .fixtures import all_trades_open_closed
from .test_definitions.helpers import get_valid_primitive_data
from aiohttp.client_exceptions import ContentTypeError

# prevent pycharm from removing the import
client = client
Expand Down Expand Up @@ -58,7 +57,7 @@ async def test_client_initializes(client, server):
error_status = [i for i in range(400, 600)]


#TEST each step of the initialization routine fails correctly
# TEST each step of the initialization routine fails correctly

@pytest.mark.asyncio
@pytest.mark.parametrize('error_status', error_status)
Expand Down Expand Up @@ -89,6 +88,7 @@ async def test_client_raises_error_on_third_initialisation_failure(client, serve
assert client.initialized == False
assert client.initializing == False


@pytest.mark.asyncio
async def test_initialize_works_with_preset_account_id(client, server):
client.account_id = '123-123-1234567-123'
Expand Down Expand Up @@ -170,8 +170,8 @@ async def test_client_time_out(client, server):


@pytest.mark.asyncio
@pytest.mark.parametrize('method', inspect.getmembers(OandaClient, lambda x: True if hasattr(x, 'shortcut') or
hasattr(x, 'endpoint') else False))
@pytest.mark.parametrize('method', inspect.getmembers(OandaClient,
lambda x: True if hasattr(x, 'shortcut') or hasattr(x, 'endpoint') else False))
async def test_client_handles_multiple_concurrent_initializations(client, server, method):
# Method is a tuple of attribute, function
client.initialization_sleep = 0 # Make this small to speed up tests
Expand All @@ -185,7 +185,11 @@ async def test_client_handles_multiple_concurrent_initializations(client, server
# Don't care if incorrect data or status is returned)
# Just want to make sure the client always initializes correctly
pass
assert client.initialized
if getattr(method, 'initialize_required', True):
assert client.initialized
else:
assert not client.initialized



@pytest.mark.asyncio
Expand Down Expand Up @@ -270,6 +274,7 @@ async def test_initialize_connection_error_resets_initialization(client, server)
assert client.initializing == False
assert client.initialized == False


def test_can_not_change_datetime_format_on_oanda_client_instance(client):
with pytest.raises(AttributeError):
client.datetime_format = 'RFC3339'
5 changes: 4 additions & 1 deletion tests/test_interface/test_api_methods.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,10 @@ async def test_client_initializes_automatically_with_every_api_method(method, se
pass # Caused by incorrect response status being returned
# Server not keeping a data stream open
# Response Not containing expected data
assert client.initialized
if getattr(method, 'initialize_required', True):
assert client.initialized
else:
assert not client.initialized


@pytest.mark.asyncio
Expand Down

0 comments on commit 10dd7da

Please sign in to comment.