diff options
author | Ismaël Bouya <ismael.bouya@normalesup.org> | 2018-04-04 13:02:56 +0200 |
---|---|---|
committer | Ismaël Bouya <ismael.bouya@normalesup.org> | 2018-04-04 13:02:56 +0200 |
commit | 7d5da019e51adea12a1ad52e07fc71c1ee1de6ab (patch) | |
tree | 6872b4a8f25e276cbc8877a2de9c1caead5a2d81 | |
parent | 79ac9364372ad0cd99f3d29b7dbc2b79dcc84bf5 (diff) | |
parent | 3b60291066e5442ce2980a6c40ea10542f24a910 (diff) | |
download | Trader-7d5da019e51adea12a1ad52e07fc71c1ee1de6ab.tar.gz Trader-7d5da019e51adea12a1ad52e07fc71c1ee1de6ab.tar.zst Trader-7d5da019e51adea12a1ad52e07fc71c1ee1de6ab.zip |
Merge branch 'dev'v1.1.2
-rw-r--r-- | .gitattributes | 2 | ||||
-rw-r--r-- | ccxt_wrapper.py | 16 | ||||
-rw-r--r-- | market.py | 3 | ||||
-rw-r--r-- | store.py | 42 | ||||
-rw-r--r-- | test.py | 55 |
5 files changed, 104 insertions, 14 deletions
diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..227f825 --- /dev/null +++ b/.gitattributes | |||
@@ -0,0 +1,2 @@ | |||
1 | *.py diff=python | ||
2 | /store.py export-subst | ||
diff --git a/ccxt_wrapper.py b/ccxt_wrapper.py index 260d49d..bedf84b 100644 --- a/ccxt_wrapper.py +++ b/ccxt_wrapper.py | |||
@@ -3,6 +3,8 @@ import decimal | |||
3 | import time | 3 | import time |
4 | from retry.api import retry_call | 4 | from retry.api import retry_call |
5 | import re | 5 | import re |
6 | from requests.exceptions import RequestException | ||
7 | from ssl import SSLError | ||
6 | 8 | ||
7 | def _cw_exchange_sum(self, *args): | 9 | def _cw_exchange_sum(self, *args): |
8 | return sum([arg for arg in args if isinstance(arg, (float, int, decimal.Decimal))]) | 10 | return sum([arg for arg in args if isinstance(arg, (float, int, decimal.Decimal))]) |
@@ -45,10 +47,16 @@ class poloniexE(poloniex): | |||
45 | self.session._parent = self | 47 | self.session._parent = self |
46 | 48 | ||
47 | def request_wrap(self, *args, **kwargs): | 49 | def request_wrap(self, *args, **kwargs): |
48 | r = self.origin_request(*args, **kwargs) | 50 | try: |
49 | self._parent._market.report.log_http_request(args[0], | 51 | r = self.origin_request(*args, **kwargs) |
50 | args[1], kwargs["data"], kwargs["headers"], r) | 52 | self._parent._market.report.log_http_request(args[0], |
51 | return r | 53 | args[1], kwargs["data"], kwargs["headers"], r) |
54 | return r | ||
55 | except (SSLError, RequestException) as e: | ||
56 | self._parent._market.report.log_http_request(args[0], | ||
57 | args[1], kwargs["data"], kwargs["headers"], e) | ||
58 | raise e | ||
59 | |||
52 | self.session.request = request_wrap.__get__(self.session, | 60 | self.session.request = request_wrap.__get__(self.session, |
53 | self.session.__class__) | 61 | self.session.__class__) |
54 | 62 | ||
@@ -28,6 +28,9 @@ class Market: | |||
28 | for key in ["user_id", "market_id", "report_path", "pg_config"]: | 28 | for key in ["user_id", "market_id", "report_path", "pg_config"]: |
29 | setattr(self, key, kwargs.get(key, None)) | 29 | setattr(self, key, kwargs.get(key, None)) |
30 | 30 | ||
31 | self.report.log_market(self.args, self.user_id, self.market_id, | ||
32 | self.report_path, self.debug) | ||
33 | |||
31 | @classmethod | 34 | @classmethod |
32 | def from_config(cls, config, args, **kwargs): | 35 | def from_config(cls, config, args, **kwargs): |
33 | config["apiKey"] = config.pop("key", None) | 36 | config["apiKey"] = config.pop("key", None) |
@@ -176,15 +176,28 @@ class ReportStore: | |||
176 | }) | 176 | }) |
177 | 177 | ||
178 | def log_http_request(self, method, url, body, headers, response): | 178 | def log_http_request(self, method, url, body, headers, response): |
179 | self.add_log({ | 179 | if isinstance(response, Exception): |
180 | "type": "http_request", | 180 | self.add_log({ |
181 | "method": method, | 181 | "type": "http_request", |
182 | "url": url, | 182 | "method": method, |
183 | "body": body, | 183 | "url": url, |
184 | "headers": headers, | 184 | "body": body, |
185 | "status": response.status_code, | 185 | "headers": headers, |
186 | "response": response.text | 186 | "status": -1, |
187 | }) | 187 | "response": None, |
188 | "error": response.__class__.__name__, | ||
189 | "error_message": str(response), | ||
190 | }) | ||
191 | else: | ||
192 | self.add_log({ | ||
193 | "type": "http_request", | ||
194 | "method": method, | ||
195 | "url": url, | ||
196 | "body": body, | ||
197 | "headers": headers, | ||
198 | "status": response.status_code, | ||
199 | "response": response.text | ||
200 | }) | ||
188 | 201 | ||
189 | def log_error(self, action, message=None, exception=None): | 202 | def log_error(self, action, message=None, exception=None): |
190 | self.print_log("[Error] {}".format(action)) | 203 | self.print_log("[Error] {}".format(action)) |
@@ -209,6 +222,17 @@ class ReportStore: | |||
209 | "action": action, | 222 | "action": action, |
210 | }) | 223 | }) |
211 | 224 | ||
225 | def log_market(self, args, user_id, market_id, report_path, debug): | ||
226 | self.add_log({ | ||
227 | "type": "market", | ||
228 | "commit": "$Format:%H$", | ||
229 | "args": vars(args), | ||
230 | "user_id": user_id, | ||
231 | "market_id": market_id, | ||
232 | "report_path": report_path, | ||
233 | "debug": debug, | ||
234 | }) | ||
235 | |||
212 | class BalanceStore: | 236 | class BalanceStore: |
213 | def __init__(self, market): | 237 | def __init__(self, market): |
214 | self.market = market | 238 | self.market = market |
@@ -71,7 +71,8 @@ class poloniexETest(unittest.TestCase): | |||
71 | super().tearDown() | 71 | super().tearDown() |
72 | 72 | ||
73 | def test__init(self): | 73 | def test__init(self): |
74 | with mock.patch("market.ccxt.poloniexE.session") as session: | 74 | with self.subTest("Nominal case"), \ |
75 | mock.patch("market.ccxt.poloniexE.session") as session: | ||
75 | session.request.return_value = "response" | 76 | session.request.return_value = "response" |
76 | ccxt = market.ccxt.poloniexE() | 77 | ccxt = market.ccxt.poloniexE() |
77 | ccxt._market = mock.Mock | 78 | ccxt._market = mock.Mock |
@@ -82,6 +83,21 @@ class poloniexETest(unittest.TestCase): | |||
82 | ccxt._market.report.log_http_request.assert_called_with('GET', 'URL', 'data', | 83 | ccxt._market.report.log_http_request.assert_called_with('GET', 'URL', 'data', |
83 | 'headers', 'response') | 84 | 'headers', 'response') |
84 | 85 | ||
86 | with self.subTest("Raising"),\ | ||
87 | mock.patch("market.ccxt.poloniexE.session") as session: | ||
88 | session.request.side_effect = market.ccxt.RequestException("Boo") | ||
89 | |||
90 | ccxt = market.ccxt.poloniexE() | ||
91 | ccxt._market = mock.Mock | ||
92 | ccxt._market.report = mock.Mock() | ||
93 | |||
94 | with self.assertRaises(market.ccxt.RequestException, msg="Boo") as cm: | ||
95 | ccxt.session.request("GET", "URL", data="data", | ||
96 | headers="headers") | ||
97 | ccxt._market.report.log_http_request.assert_called_with('GET', 'URL', 'data', | ||
98 | 'headers', cm.exception) | ||
99 | |||
100 | |||
85 | def test_nanoseconds(self): | 101 | def test_nanoseconds(self): |
86 | with mock.patch.object(market.ccxt.time, "time") as time: | 102 | with mock.patch.object(market.ccxt.time, "time") as time: |
87 | time.return_value = 123456.7890123456 | 103 | time.return_value = 123456.7890123456 |
@@ -1181,9 +1197,12 @@ class MarketTest(WebMockTestCase): | |||
1181 | with self.subTest(quiet=False): | 1197 | with self.subTest(quiet=False): |
1182 | m = market.Market(self.ccxt, self.market_args(quiet=False)) | 1198 | m = market.Market(self.ccxt, self.market_args(quiet=False)) |
1183 | report_store.assert_called_with(m, verbose_print=True) | 1199 | report_store.assert_called_with(m, verbose_print=True) |
1200 | report_store().log_market.assert_called_once() | ||
1201 | report_store.reset_mock() | ||
1184 | with self.subTest(quiet=True): | 1202 | with self.subTest(quiet=True): |
1185 | m = market.Market(self.ccxt, self.market_args(quiet=True)) | 1203 | m = market.Market(self.ccxt, self.market_args(quiet=True)) |
1186 | report_store.assert_called_with(m, verbose_print=False) | 1204 | report_store.assert_called_with(m, verbose_print=False) |
1205 | report_store().log_market.assert_called_once() | ||
1187 | 1206 | ||
1188 | @mock.patch("market.ccxt") | 1207 | @mock.patch("market.ccxt") |
1189 | def test_from_config(self, ccxt): | 1208 | def test_from_config(self, ccxt): |
@@ -4346,6 +4365,40 @@ class ReportStoreTest(WebMockTestCase): | |||
4346 | 'response': 'Hey' | 4365 | 'response': 'Hey' |
4347 | }) | 4366 | }) |
4348 | 4367 | ||
4368 | add_log.reset_mock() | ||
4369 | report_store.log_http_request("method", "url", "body", | ||
4370 | "headers", ValueError("Foo")) | ||
4371 | add_log.assert_called_once_with({ | ||
4372 | 'type': 'http_request', | ||
4373 | 'method': 'method', | ||
4374 | 'url': 'url', | ||
4375 | 'body': 'body', | ||
4376 | 'headers': 'headers', | ||
4377 | 'status': -1, | ||
4378 | 'response': None, | ||
4379 | 'error': 'ValueError', | ||
4380 | 'error_message': 'Foo', | ||
4381 | }) | ||
4382 | |||
4383 | @mock.patch.object(market.ReportStore, "add_log") | ||
4384 | def test_log_market(self, add_log): | ||
4385 | report_store = market.ReportStore(self.m) | ||
4386 | class Args: | ||
4387 | def __init__(self): | ||
4388 | self.debug = True | ||
4389 | self.quiet = False | ||
4390 | |||
4391 | report_store.log_market(Args(), 4, 1, "report", True) | ||
4392 | add_log.assert_called_once_with({ | ||
4393 | "type": "market", | ||
4394 | "commit": "$Format:%H$", | ||
4395 | "args": { "debug": True, "quiet": False }, | ||
4396 | "user_id": 4, | ||
4397 | "market_id": 1, | ||
4398 | "report_path": "report", | ||
4399 | "debug": True | ||
4400 | }) | ||
4401 | |||
4349 | @mock.patch.object(market.ReportStore, "print_log") | 4402 | @mock.patch.object(market.ReportStore, "print_log") |
4350 | @mock.patch.object(market.ReportStore, "add_log") | 4403 | @mock.patch.object(market.ReportStore, "add_log") |
4351 | def test_log_error(self, add_log, print_log): | 4404 | def test_log_error(self, add_log, print_log): |