Skip to content

Commit bc65da7

Browse files
committed
Increase default request timeout to 60 seconds and add ArangoClient.close method
1 parent 71285e0 commit bc65da7

File tree

8 files changed

+41
-29
lines changed

8 files changed

+41
-29
lines changed

README.md

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -109,5 +109,4 @@ result = graph.traverse(
109109
)
110110
```
111111

112-
Please see the [documentation](http://python-driver-for-arangodb.readthedocs.io/en/master/index.html)
113-
for more details.
112+
Please see the [documentation](https://docs.python-arango.com) for more details.

arango/client.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,11 @@ def __init__(
7575
def __repr__(self) -> str:
7676
return f"<ArangoClient {','.join(self._hosts)}>"
7777

78+
def close(self) -> None: # pragma: no cover
79+
"""Close HTTP sessions."""
80+
for session in self._sessions:
81+
session.close()
82+
7883
@property
7984
def hosts(self) -> Sequence[str]:
8085
"""Return the list of ArangoDB host URLs.

arango/connection.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,8 @@
77
]
88

99
import sys
10+
import time
1011
from abc import abstractmethod
11-
from calendar import timegm
12-
from datetime import datetime
1312
from typing import Any, Callable, Optional, Sequence, Union
1413

1514
import jwt
@@ -317,7 +316,7 @@ def send_request(self, request: Request) -> Response:
317316
if resp.error_code != 11 or resp.status_code != 401:
318317
return resp
319318

320-
now = timegm(datetime.utcnow().utctimetuple())
319+
now = int(time.time())
321320
if self._token_exp < now - self.exp_leeway: # pragma: no cover
322321
return resp
323322

arango/http.py

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@
55

66
from requests import Session
77
from requests.adapters import HTTPAdapter
8-
from requests.packages.urllib3.util.retry import Retry
98
from requests_toolbelt import MultipartEncoder
9+
from urllib3.util.retry import Retry
1010

1111
from arango.response import Response
1212
from arango.typings import Headers
@@ -66,6 +66,10 @@ def send_request(
6666
class DefaultHTTPClient(HTTPClient):
6767
"""Default HTTP client implementation."""
6868

69+
REQUEST_TIMEOUT = 60
70+
RETRY_ATTEMPTS = 3
71+
BACKOFF_FACTOR = 1
72+
6973
def create_session(self, host: str) -> Session:
7074
"""Create and return a new session/connection.
7175
@@ -75,10 +79,10 @@ def create_session(self, host: str) -> Session:
7579
:rtype: requests.Session
7680
"""
7781
retry_strategy = Retry(
78-
total=3,
79-
backoff_factor=1,
82+
total=self.RETRY_ATTEMPTS,
83+
backoff_factor=self.BACKOFF_FACTOR,
8084
status_forcelist=[429, 500, 502, 503, 504],
81-
method_whitelist=["HEAD", "GET", "OPTIONS"],
85+
allowed_methods=["HEAD", "GET", "OPTIONS"],
8286
)
8387
http_adapter = HTTPAdapter(max_retries=retry_strategy)
8488

@@ -124,7 +128,7 @@ def send_request(
124128
data=data,
125129
headers=headers,
126130
auth=auth,
127-
timeout=5,
131+
timeout=self.REQUEST_TIMEOUT,
128132
)
129133
return Response(
130134
method=method,

setup.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
from setuptools import find_packages, setup
22

33
with open("./README.md") as fp:
4-
description = fp.read()
4+
long_description = fp.read()
55

66
setup(
77
name="python-arango",
88
description="Python Driver for ArangoDB",
9-
long_description=description,
9+
long_description=long_description,
1010
long_description_content_type="text/markdown",
1111
author="Joohwan Oh",
1212
author_email="[email protected]",
@@ -19,6 +19,7 @@
1919
use_scm_version=True,
2020
setup_requires=["setuptools_scm"],
2121
install_requires=[
22+
"urllib3>=1.26.0",
2223
"dataclasses>=0.6; python_version < '3.7'",
2324
"requests",
2425
"requests_toolbelt",

tests/conftest.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,8 @@ def pytest_unconfigure(*_): # pragma: no cover
177177
for backup_id in sys_db.backup.get()["list"].keys():
178178
sys_db.backup.delete(backup_id)
179179

180+
global_data.client.close()
181+
180182

181183
# noinspection PyProtectedMember
182184
def pytest_generate_tests(metafunc):

tests/helpers.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
1-
from calendar import timegm
1+
import time
22
from collections import deque
3-
from datetime import datetime
43
from uuid import uuid4
54

65
import jwt
@@ -119,7 +118,7 @@ def generate_jwt(secret, exp=3600):
119118
:return: JWT
120119
:rtype: str
121120
"""
122-
now = timegm(datetime.utcnow().utctimetuple())
121+
now = int(time.time())
123122
return jwt.encode(
124123
payload={
125124
"iat": now,

tests/test_auth.py

Lines changed: 17 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
from arango.connection import BasicConnection, JwtConnection, JwtSuperuserConnection
22
from arango.errno import FORBIDDEN, HTTP_UNAUTHORIZED
3-
from arango.exceptions import ( # JWTSecretListError,; JWTSecretReloadError,
3+
from arango.exceptions import (
44
JWTAuthError,
5+
JWTSecretListError,
6+
JWTSecretReloadError,
57
ServerEncryptionError,
68
ServerTLSError,
79
ServerTLSReloadError,
@@ -53,6 +55,7 @@ def test_auth_jwt(client, db_name, username, password):
5355
assert err.value.error_code == HTTP_UNAUTHORIZED
5456

5557

58+
# TODO re-examine commented out code
5659
def test_auth_superuser_token(client, db_name, root_password, secret):
5760
token = generate_jwt(secret)
5861
db = client.db("_system", superuser_token=token)
@@ -66,21 +69,21 @@ def test_auth_superuser_token(client, db_name, root_password, secret):
6669
# secrets = db.jwt_secrets()
6770
# assert 'active' in secrets
6871
# assert 'passive' in secrets
69-
#
70-
# # Test get JWT secrets with bad database
71-
# with assert_raises(JWTSecretListError) as err:
72-
# bad_db.jwt_secrets()
73-
# assert err.value.error_code == FORBIDDEN
74-
#
72+
73+
# Test get JWT secrets with bad database
74+
with assert_raises(JWTSecretListError) as err:
75+
bad_db.jwt_secrets()
76+
assert err.value.error_code == FORBIDDEN
77+
7578
# # Test reload JWT secrets
7679
# secrets = db.reload_jwt_secrets()
7780
# assert 'active' in secrets
7881
# assert 'passive' in secrets
79-
#
80-
# # Test reload JWT secrets with bad database
81-
# with assert_raises(JWTSecretReloadError) as err:
82-
# bad_db.reload_jwt_secrets()
83-
# assert err.value.error_code == FORBIDDEN
82+
83+
# Test reload JWT secrets with bad database
84+
with assert_raises(JWTSecretReloadError) as err:
85+
bad_db.reload_jwt_secrets()
86+
assert err.value.error_code == FORBIDDEN
8487

8588
# Test get TLS data
8689
result = db.tls()
@@ -100,7 +103,7 @@ def test_auth_superuser_token(client, db_name, root_password, secret):
100103
bad_db.reload_tls()
101104
assert err.value.error_code == FORBIDDEN
102105

103-
# # Test reload TLS
106+
# # Test get encryption
104107
# result = db.encryption()
105108
# assert isinstance(result, dict)
106109

@@ -113,7 +116,7 @@ def test_auth_superuser_token(client, db_name, root_password, secret):
113116
def test_auth_jwt_expiry(client, db_name, root_password, secret):
114117
# Test automatic token refresh on expired token.
115118
db = client.db("_system", "root", root_password, auth_method="jwt")
116-
expired_token = generate_jwt(secret, exp=0)
119+
expired_token = generate_jwt(secret, exp=-1000)
117120
db.conn._token = expired_token
118121
db.conn._auth_header = f"bearer {expired_token}"
119122
assert isinstance(db.version(), str)

0 commit comments

Comments
 (0)