Skip to content

Commit

Permalink
Array.get_id supports both int and str id's
Browse files Browse the repository at this point in the history
Updated error message for failure to create `Model` object

Added attributes to attributes module.

Removed 'health' primitives
  • Loading branch information
jamespeterschinner committed Dec 26, 2017
1 parent 8052701 commit cc0026a
Show file tree
Hide file tree
Showing 27 changed files with 317 additions and 419 deletions.
18 changes: 10 additions & 8 deletions async_v20/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
from .definitions.types import ArrayTransaction
from .endpoints.annotations import Authorization, SinceTransactionID, LastTransactionID
from .interface import *
from .interface.account import AccountInterface



async def sleep(s=0.0):
Expand All @@ -24,9 +24,8 @@ async def sleep(s=0.0):


class OandaClient(AccountInterface, InstrumentInterface, OrderInterface, PositionInterface,
PricingInterface,
TradeInterface,
TransactionInterface, UserInterface):
PricingInterface, TradeInterface, TransactionInterface, UserInterface,
HealthInterface):
"""
Create an API context for v20 access
Expand All @@ -52,7 +51,7 @@ class OandaClient(AccountInterface, InstrumentInterface, OrderInterface, Positio
"""
headers = {'Content-Type': 'application/json', 'Connection': 'keep-alive',
'OANDA-Agent': 'async_v20_' + __version__,}
'OANDA-Agent': 'async_v20_' + __version__}

default_parameters = {}

Expand Down Expand Up @@ -95,12 +94,12 @@ def max_simultaneous_connections(self, value):
def datetime_format(self):
return self._datetime_format


def __init__(self, token=None, account_id=None, format_order_requests=False,
max_transaction_history=100,
rest_host='api-fxpractice.oanda.com', rest_port=443,
rest_scheme='https', stream_host='stream-fxpractice.oanda.com', stream_port=None,
stream_scheme='https', datetime_format='UNIX', rest_timeout=10, stream_timeout=60,
stream_scheme='https', health_host='api-status.oanda.com', health_port=80, health_scheme='http',
datetime_format='UNIX', rest_timeout=10, stream_timeout=60,
max_requests_per_second=99, max_simultaneous_connections=10, loop=None):

if loop is None:
Expand All @@ -123,7 +122,10 @@ def __init__(self, token=None, account_id=None, format_order_requests=False,
# v20 STREAM API URL
stream_host = partial(URL.build, host=stream_host, port=stream_port, scheme=stream_scheme)

self.hosts = {'REST': rest_host, 'STREAM': stream_host}
# V20 API health URL
health_host = partial(URL.build, host=health_host, port=health_port, scheme=health_scheme)

self.hosts = {'REST': rest_host, 'STREAM': stream_host, 'HEALTH': health_host}

# The timeout to use when making a polling request with the
# v20 REST server
Expand Down
9 changes: 7 additions & 2 deletions async_v20/definitions/attributes.py
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,9 @@
'loss_quote_home_conversion_factor': 'loss_quote_home_conversion_factor',
'guaranteedExecutionFee': 'guaranteed_execution_fee',
'guaranteed_execution_fee': 'guaranteed_execution_fee', 'halfSpreadCost': 'half_spread_cost',
'half_spread_cost': 'half_spread_cost'}
'half_spread_cost': 'half_spread_cost', 'description': 'description', 'list': 'list',
'current-event': 'current_event', 'url': 'url', 'sid': 'sid', 'message': 'message',
'informational': 'informational', 'level': 'level', 'image': 'image'}

json_attributes = {'long': 'long', 'short': 'short', 'default': 'default', 'reduce_first': 'reduceFirst',
'reduce_only': 'reduceOnly', 'open_only': 'openOnly', 'timestamp': 'timestamp',
Expand Down Expand Up @@ -247,4 +249,7 @@
'country': 'country', 'email_address': 'emailAddress', 'fifo': 'FIFO', 'partial_fill': 'partialFill',
'gain_quote_home_conversion_factor': 'gainQuoteHomeConversionFactor',
'loss_quote_home_conversion_factor': 'lossQuoteHomeConversionFactor',
'guaranteed_execution_fee': 'guaranteedExecutionFee', 'half_spread_cost': 'halfSpreadCost'}
'guaranteed_execution_fee': 'guaranteedExecutionFee', 'half_spread_cost': 'halfSpreadCost',
'description': 'description', 'list': 'list',
'current_event':'current-event', 'url': 'url', 'sid': 'sid', 'message': 'message',
'informational': 'informational', 'level': 'level', 'image': 'image'}
6 changes: 3 additions & 3 deletions async_v20/definitions/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -278,7 +278,7 @@ def construct_items(data):
# It's useful to be able to lookup items in an array
# By the items attributes. If not id, instrument
try:
_ids.update({getattr(item, 'id'): index})
_ids.update({str(getattr(item, 'id')): index})
except AttributeError:
key = getattr(item, 'instrument', getattr(item, 'name', None))
if key:
Expand All @@ -297,7 +297,7 @@ def construct_items(data):

def get_id(self, id_, default=None):
try:
return self[self._ids[int(id_)]]
return self[self._ids[str(id_)]]
except KeyError:
return default

Expand Down Expand Up @@ -335,6 +335,6 @@ def create_attribute(typ, data):
# when an error code has been returned
# A none value should be returned if this is the case
if typ is not None:
raise TypeError(f'Could note create {typ} from {data}')
raise TypeError(f'Could note create {typ} from {data}. {type(data)}')
else:
return result
39 changes: 22 additions & 17 deletions async_v20/health/types.py → async_v20/definitions/health_types.py
Original file line number Diff line number Diff line change
@@ -1,45 +1,50 @@
from ..definitions.base import Model, Array
from .primitives import *
from .base import Model, Array


class ServiceList(Model):
"""A collection of related services
"""

def __new__(cls, id: Id, name: Name, description: Description, url: URL):
def __new__(cls, id: str, name: str, description: str, url: str):
return super().__new__(**ServiceList._preset_arguments, **locals())


class ArrayServiceList(Array):
_contains = ServiceList

class Service(Model):
"""A log of all events that have occurred in the past.
The current state of a service is represented by the current status of the service."""

def __new__(cls, id: Id, name: Name, description: Description,
list: ServiceList, current_event: CurrentEvent, url: URL):
return super().__new__(**Service._preset_arguments, **locals())

class ArrayService(Array):
_contains = Service

class Status(Model):
"""The current event of a status"""

def __new__(cls, id: Id, name: Name, description: Description, url: URL,
level: Level, image: Image, default: Default):
def __new__(cls, id: str, name: str, description: str, url: str,
level: str, image: str, default: bool):
return super().__new__(**Status._preset_arguments, **locals())


class ArrayStatus(Array):
_contains = Status


class Event(Model):
"""Anything Interesting that has happened to a Service"""

def __new__(cls, sid: Sid, message: Message, timestamp: Timestamp,
url: URL, status: Status, informational: Informational):
def __new__(cls, sid: str, message: str, timestamp: str,
url: str, status: Status, informational: bool):
return super().__new__(**Event._preset_arguments, **locals())


class ArrayEvent(Array):
_contains = Event


class Service(Model):
"""A log of all events that have occurred in the past.
The current state of a service is represented by the current status of the service."""

def __new__(cls, id: str, name: str, description: str,
list: ServiceList, current_event: Event, url: str):
return super().__new__(**Service._preset_arguments, **locals())


class ArrayService(Array):
_contains = Service
2 changes: 2 additions & 0 deletions async_v20/definitions/primitives.py
Original file line number Diff line number Diff line change
Expand Up @@ -1191,3 +1191,5 @@ class TransactionType(str, Primitive):
def __new__(cls, value):
assert domain_check(value, possible_values=cls.values)
return super().__new__(cls, value)

# Health Primitives
52 changes: 14 additions & 38 deletions async_v20/endpoints/account.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
from .annotations import SinceTransactionID
from .annotations import Alias
from .annotations import Authorization
from .annotations import Instruments
from .annotations import Alias
from .base import EndPoint
from .annotations import SinceTransactionID
from .base import EndPoint, HEADER, PATH, QUERY
from ..definitions.primitives import *
from ..definitions.types import *

Expand All @@ -21,9 +21,7 @@ class GETAccounts(EndPoint):
description = 'Get a list of all Accounts authorized for the provided token.'

# parameters required to send to endpoint
parameters = [
{'name': 'Authorization', 'located': 'header', 'type': Authorization, 'description': 'str'},
]
parameters = {Authorization: (HEADER, 'Authorization')}

# valid responses
responses = {200: {'accounts': ArrayAccountProperties}}
Expand All @@ -44,13 +42,8 @@ class GETAccountID(EndPoint):
'Full pending Order, open Trade and open Position representations are provided.'

# parameters required to send to endpoint
parameters = [
{'name': 'Authorization', 'located': 'header', 'type': Authorization, 'description': 'str'},
{'name': 'Accept-Datetime-Format', 'located': 'header', 'type': AcceptDatetimeFormat,
'description': 'AcceptDatetimeFormat'},
{'name': 'accountID', 'located': 'path', 'type': AccountID, 'description': 'AccountID'},
]

parameters = {Authorization: (HEADER, 'Authorization'), AcceptDatetimeFormat: (HEADER, 'Accept-Datetime-Format'),
AccountID: (PATH, 'accountID')}
# valid responses
responses = {200: {'account': Account, 'lastTransactionID': TransactionID}}

Expand All @@ -69,12 +62,8 @@ class GETAccountIDSummary(EndPoint):
description = 'Get a summary for a single Account that a client has access to.'

# parameters required to send to endpoint
parameters = [
{'name': 'Authorization', 'located': 'header', 'type': Authorization, 'description': 'str'},
{'name': 'Accept-Datetime-Format', 'located': 'header', 'type': AcceptDatetimeFormat,
'description': 'AcceptDatetimeFormat'},
{'name': 'accountID', 'located': 'path', 'type': AccountID, 'description': 'AccountID'},
]
parameters = {Authorization: (HEADER, 'Authorization'), AcceptDatetimeFormat: (HEADER, 'Accept-Datetime-Format'),
AccountID: (PATH, 'accountID')}

# valid responses
responses = {200: {'account': AccountSummary, 'lastTransactionID': TransactionID}}
Expand All @@ -97,12 +86,8 @@ class GETAccountIDInstruments(EndPoint):
'Accounts owned by a single user.'

# parameters required to send to endpoint
parameters = [
{'name': 'Authorization', 'located': 'header', 'type': Authorization, 'description': 'str'},
{'name': 'accountID', 'located': 'path', 'type': AccountID, 'description': 'AccountID'},
{'name': 'instruments', 'located': 'query', 'type': Instruments,
'description': 'List of InstrumentName (csv)'},
]
parameters = {Authorization: (HEADER, 'Authorization'), AccountID: (PATH, 'accountID'),
Instruments: (QUERY, 'instruments')}

# valid responses
responses = {200: {'instruments': ArrayInstrument, 'lastTransactionID': TransactionID}}
Expand All @@ -122,12 +107,8 @@ class PATCHAccountIDConfiguration(EndPoint):
description = 'Set the client-configurable portions of an Account.'

# parameters required to send to endpoint
parameters = [
{'name': 'Authorization', 'located': 'header', 'type': Authorization, 'description': 'str'},
{'name': 'Accept-Datetime-Format', 'located': 'header', 'type': AcceptDatetimeFormat,
'description': 'AcceptDatetimeFormat'},
{'name': 'accountID', 'located': 'path', 'type': AccountID, 'description': 'AccountID'},
]
parameters = {Authorization: (HEADER, 'Authorization'), AcceptDatetimeFormat: (HEADER, 'Accept-Datetime-Format'),
AccountID: (PATH, 'accountID')}

# valid responses
responses = {200: {'clientConfigureTransaction': ClientConfigureTransaction, 'lastTransactionID': TransactionID},
Expand All @@ -153,13 +134,8 @@ class GETAccountIDChanges(EndPoint):
description = 'Endpoint used to poll an Account for its current state and changes since a specified TransactionID.'

# parameters required to send to endpoint
parameters = [
{'name': 'Authorization', 'located': 'header', 'type': Authorization, 'description': 'str'},
{'name': 'Accept-Datetime-Format', 'located': 'header', 'type': AcceptDatetimeFormat,
'description': 'AcceptDatetimeFormat'},
{'name': 'accountID', 'located': 'path', 'type': AccountID, 'description': 'AccountID'},
{'name': 'sinceTransactionID', 'located': 'query', 'type': SinceTransactionID, 'description': 'TransactionID'},
]
parameters = {Authorization: (HEADER, 'Authorization'), AcceptDatetimeFormat: (HEADER, 'Accept-Datetime-Format'),
AccountID: (PATH, 'accountID'), SinceTransactionID: (QUERY, 'sinceTransactionID')}

# valid responses
responses = {200: {'changes': AccountChanges, 'state': AccountChangesState, 'lastTransactionID': TransactionID}}
Expand Down
1 change: 1 addition & 0 deletions async_v20/endpoints/annotations.py
Original file line number Diff line number Diff line change
Expand Up @@ -194,3 +194,4 @@ class FromTransactionID(TransactionID):
class ToTransactionID(TransactionID):
"""A TransactionID to be used as the ending period of a query"""
pass

18 changes: 10 additions & 8 deletions async_v20/endpoints/base.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
from typing import List

HEADER = 'header'
PATH = 'path'
QUERY = 'query'
HEALTH = 'HEALTH'

class EndPoint(object):
"""Base object representation of an endpoint"""
Expand All @@ -11,19 +13,19 @@ class EndPoint(object):
path = ()

# the HTTP verb to use for this endpoint
method = str
method = ''

# description of endpoint
description = str
description = ''

# parameters required to send to endpoint
parameters = List[dict]
parameters = {}

# valid responses
responses = List[dict]
responses = {}

# error msgs'
error = List[str]
error = ()

# json format the data body as per the response_schema below
request_schema = dict()
request_schema = {}

0 comments on commit cc0026a

Please sign in to comment.