Skip to content

Commit

Permalink
Merge branch 'dev'
Browse files Browse the repository at this point in the history
  • Loading branch information
tariqdaouda committed Jan 11, 2022
2 parents db758bf + ba414b7 commit 57eba56
Show file tree
Hide file tree
Showing 7 changed files with 78 additions and 69 deletions.
14 changes: 14 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
@@ -1,3 +1,17 @@
2.0.1
=====

* Fixed max retries for write conflicts

2.0
=====

* changed the default value of reject_zero in NotNull from True to False
* added to_default function to reset a document to its default values
* fixed bug in default documents where default values could be overwritten
* default value for fields is now None
* defaual value for fields can now be a callable

1.3.5
=====

Expand Down
89 changes: 25 additions & 64 deletions pyArango/collection.py
Original file line number Diff line number Diff line change
Expand Up @@ -118,8 +118,8 @@ def __repr__(self):

class Field(object):
"""The class for defining pyArango fields."""
def __init__(self, validators = None, default = ""):
"""validators must be a list of validators"""
def __init__(self, validators = None, default = None):
"""validators must be a list of validators. default can also be a callable"""
if not validators:
validators = []
self.validators = validators
Expand Down Expand Up @@ -238,16 +238,6 @@ class Collection(with_metaclass(Collection_metaclass, object)):

def __init__(self, database, jsonData):

def getDefaultDoc(fields, dct):
for k, v in fields.items():
if isinstance(v, dict):
dct[k] = getDefaultDoc(fields[k], {})
elif isinstance(v, Field):
dct[k] = v.default
else:
raise ValueError("Field '%s' is of invalid type '%s'" % (k, type(v)) )
return dct

self.database = database
self.connection = self.database.connection
self.name = self.__class__.__name__
Expand All @@ -267,13 +257,30 @@ def getDefaultDoc(fields, dct):
"fulltext" : {},
}
self.indexes_by_name = {}

self.defaultDocument = getDefaultDoc(self._fields, {})
# self.defaultDocument = None #getDefaultDoc(self._fields, {})
self._isBulkInProgress = False
self._bulkSize = 0
self._bulkCache = []
self._bulkMode = BulkMode.NONE

def getDefaultDocument(self, fields=None, dct=None):
if dct is None:
dct = {}
if fields is None:
fields = self._fields

for k, v in fields.items():
if isinstance(v, dict):
dct[k] = self.getDefaultDocument(fields[k], None)
elif isinstance(v, Field):
if callable(v.default):
dct[k] = v.default()
else :
dct[k] = v.default
else:
raise ValueError("Field '%s' is of invalid type '%s'" % (k, type(v)) )
return dct

def getURL(self):
return "%s/collection/%s" % (self.database.getURL(), self.name)

Expand Down Expand Up @@ -316,7 +323,9 @@ def delete(self):

def createDocument(self, initDict = None):
"""create and returns a completely empty document or one populated with initDict"""
res = dict(self.defaultDocument)
# res = dict(self.defaultDocument)
res = self.getDefaultDocument()

if initDict is not None:
res.update(initDict)

Expand Down Expand Up @@ -638,55 +647,6 @@ def validatePrivate(self, field, value):
self._fields[field].validate(value)
return True

# @classmethod
# def validateField(cls, fieldName, value):
# """checks if 'value' is valid for field 'fieldName'. If the validation is unsuccessful, raises a SchemaViolation or a ValidationError.
# for nested dicts ex: {address : { street: xxx} }, fieldName can take the form address.street
# """

# def _getValidators(cls, fieldName):
# path = fieldName.split(".")
# v = cls._fields
# for k in path:
# try:
# v = v[k]
# except KeyError:
# return None
# return v

# field = _getValidators(cls, fieldName)

# if field is None:
# if not cls._validation["allow_foreign_fields"]:
# raise SchemaViolation(cls, fieldName)
# else:
# return field.validate(value)

# @classmethod
# def validateDct(cls, dct):
# "validates a dictionary. The dictionary must be defined such as {field: value}. If the validation is unsuccefull, raises an InvalidDocument"
# def _validate(dct, res, parentsStr=""):
# for k, v in dct.items():
# if len(parentsStr) == 0:
# ps = k
# else:
# ps = "%s.%s" % (parentsStr, k)

# if type(v) is dict:
# _validate(v, res, ps)
# elif k not in cls.arangoPrivates:
# try:
# cls.validateField(ps, v)
# except (ValidationError, SchemaViolation) as e:
# res[k] = str(e)

# res = {}
# _validate(dct, res)
# if len(res) > 0:
# raise InvalidDocument(res)

# return True

@classmethod
def hasField(cls, fieldName):
"""returns True/False wether the collection has field K in it's schema. Use the dot notation for the nested fields: address.street"""
Expand Down Expand Up @@ -982,3 +942,4 @@ def __enter__(self):
return self.coll
def __exit__(self, type, value, traceback):
self.coll._finalizeBatch();

14 changes: 11 additions & 3 deletions pyArango/connection.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@

from .ca_certificate import CA_Certificate

from json.decoder import JSONDecodeError

class JsonHook(object):
"""This one replaces requests' original json() function. If a call to json() fails, it will print a message with the request content"""
def __init__(self, ret):
Expand Down Expand Up @@ -50,11 +52,17 @@ def __call__(self, *args, **kwargs):
kwargs["verify"] = self.verify

try:
status_code = 1200
do_retry = True
retry = 0
while status_code == 1200 and retry < self.max_conflict_retries :
while do_retry and retry < self.max_conflict_retries :
ret = self.fct(*args, **kwargs)
status_code = ret.status_code
do_retry = ret.status_code == 1200
try :
data = ret.json()
do_retry = do_retry or ("errorNum" in data and data["errorNum"] == 1200)
except JSONDecodeError:
pass

retry += 1
except:
print ("===\nUnable to establish connection, perhaps arango is not running.\n===")
Expand Down
4 changes: 4 additions & 0 deletions pyArango/document.py
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,10 @@ def reset(self, collection, jsonFieldInit = None, on_load_validation=False) :

self.modified = True

def to_default(self):
"""reset the document to the default values"""
self.reset(self.collection, self.collection.getDefaultDocument())

def validate(self):
"""validate the document"""
self._store.validate()
Expand Down
22 changes: 22 additions & 0 deletions pyArango/tests/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,28 @@ def deleteManyUsersBulk(self, collection, batchSize, skip, docs):
count += 1
return count

# @unittest.skip("stand by")
def test_to_default(self):
class theCol(Collection):
_fields = {
'address' : {
'street' : Field(default="Paper street"),
},
"name": Field(default = "Tyler Durden")
}

col = self.db.createCollection("theCol")
doc = col.createDocument()
self.assertEqual(doc["address"]["street"], "Paper street")
self.assertEqual(doc["name"], "Tyler Durden")
doc["address"]["street"] = "North street"
doc["name"] = "Jon Snow"
self.assertEqual(doc["address"]["street"], "North street")
self.assertEqual(doc["name"], "Jon Snow")
doc.to_default()
self.assertEqual(doc["address"]["street"], "Paper street")
self.assertEqual(doc["name"], "Tyler Durden")

# @unittest.skip("stand by")
def test_bulk_operations(self):
(collection, docs) = self.createManyUsersBulk(55, 17)
Expand Down
2 changes: 1 addition & 1 deletion pyArango/validation.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ def __str__(self):

class NotNull(Validator):
"""Checks that the Field has a non null value. False is not considered a Null Value"""
def __init__(self, reject_zero=True, reject_empty_string=True):
def __init__(self, reject_zero=False, reject_empty_string=True):
self.reject_zero = reject_zero
self.reject_empty_string = reject_empty_string

Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
setup(
name='pyArango',

version='1.3.5',
version='2.0.1',

description='An easy to use python driver for ArangoDB with built-in validation',
long_description=long_description,
Expand Down

0 comments on commit 57eba56

Please sign in to comment.