Skip to content

Commit 57532a9

Browse files
committed
Another giant refactoring
1 parent 57f3dc8 commit 57532a9

15 files changed

+538
-317
lines changed

README.md

+42-7
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ Databases
4040
---------
4141

4242
```python
43-
# Listing the databases
43+
# List all databases
4444
conn.databases
4545
conn.databases["user"]
4646
conn.databases["system"]
@@ -51,7 +51,7 @@ conn.create_database("my_database")
5151
# Delete a database
5252
conn.delete_database("my_database")
5353

54-
# Retrieving information on the default ("_system") database
54+
# Retrieve information on the default ("_system") database
5555
conn.name # equivalent to conn.db("_system").name
5656
conn.collections # equivalent to conn.db("_system").collections
5757
conn.id # equivalent to conn.db("_system").id
@@ -60,7 +60,7 @@ conn.is_system # equivalent to conn.db("_system").is_system
6060
conn.is_edge # equivalent to conn.db("_system").is_system
6161
conn.is_volatile # equivalent to conn.db("_system").is_system
6262

63-
# Get information on a specific database
63+
# Retrieve information on a specific database
6464
conn.db("db01").name
6565
conn.db("db01").collections
6666
conn.db("db02").id
@@ -80,9 +80,44 @@ conn.db("my_database").*
8080

8181
User Management
8282
---------------
83+
```python
84+
85+
# List all users
86+
conn.users
87+
88+
# Create a new user
89+
conn.create_user("username", "password1")
90+
91+
# Update a user
92+
conn.update_user("username", "password2", change_password=True)
93+
94+
# Replace a user
95+
conn.replace_user("username", "password3")
96+
97+
# Delete a user
98+
conn.delete_user("username")
99+
```
83100

84101
Monitoring
85102
----------
103+
```python
104+
105+
# Retrieve global server log
106+
conn.read_log(level="debug")
107+
108+
# Create a new user
109+
conn.create_user("username", "password1")
110+
111+
# Update a user
112+
conn.update_user("username", "password2", change_password=True)
113+
114+
# Replace a user
115+
conn.replace_user("username", "password3")
116+
117+
# Delete a user
118+
conn.delete_user("username")
119+
```
120+
86121

87122
AQL Functions
88123
-------------
@@ -134,16 +169,16 @@ my_database.collections["user"]
134169
my_database.collecitons["system"]
135170
my_database.collections["all"]
136171

137-
# Create a new collection
172+
# Create a collection
138173
my_database.create_collection("new_collection")
139174

140-
# Create a new edge collection
141-
my_database.create_collection("new_ecol", is_edge=True)
175+
# Create an edge collection
176+
my_database.create_collection("new_ecollection", is_edge=True)
142177

143178
# Rename a collection
144179
my_database.rename_collection("new_collection", "my_collection")
145180

146-
# Delete a collection from the database
181+
# Delete a collection
147182
my_database.delete_collection("my_collection")
148183

149184
# Retrieve collection information

arango/__init__.py

+97-17
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,21 @@
1-
"""ArangoDB Top-Level API."""
1+
"""ArangoDB's Top-Level API."""
22

33
from arango.database import Database
44
from arango.api import API
55
from arango.exceptions import *
66
from arango.constants import HTTP_OK, LOG_LEVELS
7-
from arango.clients import DefaultArangoClient
7+
from arango.clients import DefaultClient
88
from arango.utils import uncamelify
99

1010

1111
class Arango(object):
12-
"""Wrapper for ArangoDB's top-level API."""
12+
"""Wrapper for ArangoDB's top-level APIs:
13+
14+
1. Database Management
15+
2. User Management
16+
3. Administration & Monitoring
17+
4. Miscellaneous Functions
18+
"""
1319

1420
def __init__(self, protocol="http", host="localhost", port=8529,
1521
username="root", password="", client=None):
@@ -26,8 +32,8 @@ def __init__(self, protocol="http", host="localhost", port=8529,
2632
:param password: ArangoDB password (default: '')
2733
:type password: str
2834
:param client: HTTP client for this wrapper to use
29-
:type client: arango.clients.base.BaseArangoClient or None
30-
:raises: ArangoConnectionError
35+
:type client: arango.clients.base.BaseClient or None
36+
:raises: ConnectionError
3137
"""
3238
self.protocol = protocol
3339
self.host = host
@@ -40,7 +46,7 @@ def __init__(self, protocol="http", host="localhost", port=8529,
4046
self.client = client
4147
else:
4248
client_init_data = {"auth": (self.username, self.password)}
43-
self.client = DefaultArangoClient(client_init_data)
49+
self.client = DefaultClient(client_init_data)
4450

4551
# Initialize the ArangoDB API wrapper object
4652
self.api = API(
@@ -55,7 +61,7 @@ def __init__(self, protocol="http", host="localhost", port=8529,
5561
# Check the connection by requesting a header
5662
res = self.api.head("/_api/version")
5763
if res.status_code not in HTTP_OK:
58-
raise ArangoConnectionError(res)
64+
raise ConnectionError(res)
5965

6066
# Cache for Database objects
6167
self._database_cache = {}
@@ -91,6 +97,10 @@ def _invalidate_database_cache(self):
9197
)
9298
)
9399

100+
###########################
101+
# Miscellaneous Functions #
102+
###########################
103+
94104
@property
95105
def version(self):
96106
"""Return the version of ArangoDB.
@@ -104,9 +114,9 @@ def version(self):
104114
raise VersionGetError(res)
105115
return res.obj["version"]
106116

107-
#############
108-
# Databases #
109-
#############
117+
#######################
118+
# Database Management #
119+
#######################
110120

111121
@property
112122
def databases(self):
@@ -182,13 +192,13 @@ def delete_database(self, name, safe_delete=False):
182192
raise DatabaseDeleteError(res)
183193
self._invalidate_database_cache()
184194

185-
#########
186-
# Users #
187-
#########
195+
###################
196+
# User Management #
197+
###################
188198

189199
@property
190200
def users(self):
191-
"""Return the details on all users.
201+
"""Return details on all users.
192202
193203
:returns: a dictionary mapping user names to their information
194204
:rtype: dict
@@ -209,6 +219,26 @@ def users(self):
209219

210220
def create_user(self, username, password, active=None, extra=None,
211221
change_password=None):
222+
"""Create a new user.
223+
224+
if ``change_password`` is set to true, the only operation allowed by
225+
the user will be ``self.replace_user`` or ``self.update_user``. All
226+
other operations executed by the user will result in an HTTP 403.
227+
228+
:param username: the name of the user
229+
:type username: str
230+
:param password: the user password
231+
:type password: str
232+
:param active: whether the user is active
233+
:type active: bool or None
234+
:param extra: any extra data about the user
235+
:type extra: dict or None
236+
:param change_password: whether the user must change the password
237+
:type change_password: bool or None
238+
:returns: the information about the new user
239+
:rtype: dict
240+
:raises: UserCreateError
241+
"""
212242
data = {"user": username, "passwd": password}
213243
if active is not None:
214244
data["active"] = active
@@ -228,6 +258,26 @@ def create_user(self, username, password, active=None, extra=None,
228258

229259
def update_user(self, username, password=None, active=None, extra=None,
230260
change_password=None):
261+
"""Update an existing user.
262+
263+
if ``change_password`` is set to true, the only operation allowed by
264+
the user will be ``self.replace_user`` or ``self.update_user``. All
265+
other operations executed by the user will result in an HTTP 403.
266+
267+
:param username: the name of the existing user
268+
:type username: str
269+
:param password: the user password
270+
:type password: str
271+
:param active: whether the user is active
272+
:type active: bool or None
273+
:param extra: any extra data about the user
274+
:type extra: dict or None
275+
:param change_password: whether the user must change the password
276+
:type change_password: bool or None
277+
:returns: the information about the updated user
278+
:rtype: dict
279+
:raises: UserUpdateError
280+
"""
231281
data = {}
232282
if password is not None:
233283
data["password"] = password
@@ -251,6 +301,26 @@ def update_user(self, username, password=None, active=None, extra=None,
251301

252302
def replace_user(self, username, password, active=None, extra=None,
253303
change_password=None):
304+
"""Replace an existing user.
305+
306+
if ``change_password`` is set to true, the only operation allowed by
307+
the user will be ``self.replace_user`` or ``self.update_user``. All
308+
other operations executed by the user will result in an HTTP 403.
309+
310+
:param username: the name of the existing user
311+
:type username: str
312+
:param password: the user password
313+
:type password: str
314+
:param active: whether the user is active
315+
:type active: bool or None
316+
:param extra: any extra data about the user
317+
:type extra: dict or None
318+
:param change_password: whether the user must change the password
319+
:type change_password: bool or None
320+
:returns: the information about the replaced user
321+
:rtype: dict
322+
:raises: UserReplaceError
323+
"""
254324
data = {"user": username, "password": password}
255325
if active is not None:
256326
data["active"] = active
@@ -271,15 +341,25 @@ def replace_user(self, username, password, active=None, extra=None,
271341
}
272342

273343
def delete_user(self, username, safe_delete=False):
344+
"""Delete an existing user.
345+
346+
:param username: the name of the user
347+
:type username: str
348+
:param safe_delete: ignores HTTP 404 if set to True
349+
:type safe_delete: bool
350+
:returns: True if the operation succeeds
351+
:rtype: bool
352+
:raises: UserDeleteError
353+
"""
274354
res = self.api.delete("/_api/user/{user}".format(user=username))
275355
if res.status_code not in HTTP_OK:
276356
if not (res.status_code == 404 and safe_delete):
277357
raise UserDeleteError(res)
278358
return True
279359

280-
##############
281-
# Monitoring #
282-
##############
360+
###############################
361+
# Administration & Monitoring #
362+
###############################
283363

284364
def read_log(self, upto=None, level=None, start=None, size=None,
285365
offset=None, search=None, sort=None):

arango/api.py

+27-5
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
1-
"""ArangoDB Request Client."""
1+
"""Wrapper for making REST API calls to ArangoDB."""
22

33
import json
44

55
from arango.constants import DEFAULT_DATABASE
6-
from arango.clients import DefaultArangoClient
6+
from arango.clients import DefaultClient
77
from arango.utils import is_string
88

99

1010
class API(object):
11-
"""A simple wrapper for making REST API calls to ArangoDB.
11+
"""Wrapper object which makes REST API calls to ArangoDB.
1212
1313
:param protocol: the internet transfer protocol (default: 'http')
1414
:type protocol: str
@@ -23,7 +23,7 @@ class API(object):
2323
:param database: the ArangoDB database to point the API calls to
2424
:type database: str
2525
:param client: HTTP client for this wrapper to use
26-
:type client: arango.clients.base.BaseArangoClient or None
26+
:type client: arango.clients.base.BaseClient or None
2727
"""
2828

2929
def __init__(self, protocol="http", host="localhost", port=8529,
@@ -44,7 +44,7 @@ def __init__(self, protocol="http", host="localhost", port=8529,
4444
self.client = client
4545
else:
4646
client_init_data = {"auth": (self.username, self.password)}
47-
self.client = DefaultArangoClient(client_init_data)
47+
self.client = DefaultClient(client_init_data)
4848

4949
def head(self, path, params=None, headers=None):
5050
"""Call a HEAD method in ArangoDB's REST API.
@@ -168,3 +168,25 @@ def delete(self, path, params=None, headers=None):
168168
headers=headers,
169169
auth=(self.username, self.password)
170170
)
171+
172+
def options(self, path, data=None, params=None, headers=None):
173+
"""Call an OPTIONS method in ArangoDB's REST API.
174+
175+
:param path: the API path (e.g. '/_api/version')
176+
:type path: str
177+
:param data: the request payload
178+
:type data: str or dict or None
179+
:param params: the request parameters
180+
:type params: dict or None
181+
:param headers: the request headers
182+
:type headers: dict or None
183+
:returns: the ArangoDB http response
184+
:rtype: arango.response.Response
185+
"""
186+
return self.client.options(
187+
url=self.url_prefix + path,
188+
data=data if is_string(data) else json.dumps(data),
189+
params=params,
190+
headers=headers,
191+
auth=(self.username, self.password)
192+
)

arango/clients/__init__.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
from arango.clients.default import DefaultArangoClient
1+
from arango.clients.default import DefaultClient

arango/clients/base.py

+20-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
from abc import ABCMeta, abstractmethod
44

55

6-
class BaseArangoClient(object):
6+
class BaseClient(object):
77
"""Base class for ArangoDB clients.
88
99
The methods MUST return an ``arango.response.Response`` object.
@@ -118,3 +118,22 @@ def delete(self, url, params=None, headers=None, auth=None):
118118
:rtype: arango.response.Response
119119
"""
120120
raise NotImplementedError
121+
122+
@abstractmethod
123+
def options(self, url, data=None, params=None, headers=None, auth=None):
124+
"""HTTP OPTIONS method.
125+
126+
:param url: request URL
127+
:type url: str
128+
:param data: request payload
129+
:type data: str or dict or None
130+
:param params: request parameters
131+
:type params: dict or None
132+
:param headers: request headers
133+
:type headers: dict or None
134+
:param auth: username and password tuple
135+
:type auth: tuple or None
136+
:returns: ArangoDB http response object
137+
:rtype: arango.response.Response
138+
"""
139+
raise NotImplementedError

0 commit comments

Comments
 (0)