Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Migrations dev #563

Open
wants to merge 201 commits into
base: orm
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
201 commits
Select commit Hold shift + click to select a range
667f022
New migrations
sashaaero Sep 5, 2019
0b290c5
Backport migrations to Python2
kozlovsky Mar 11, 2020
aa5ed43
Fix57:Problems with rename migration
Mar 11, 2020
add24a3
Fix: Optional-Optional relation incorrect attributes order for key of…
Mar 12, 2020
88452f8
SQLite upgrade
Mar 16, 2020
9585740
Remove sql_op decorator from get_inline_sql.
Mar 13, 2020
6694e3c
Fix 61: No such column
Mar 18, 2020
6655d04
In case of changing attribute type to composite type (with options) 2…
May 7, 2020
f87f6b5
AddSymmetricRelation operation added
May 12, 2020
87761b3
Reverse index support
May 14, 2020
ae99341
Implicit_fk_indexes parameter added for provider
May 14, 2020
e19486e
Remove unused argument
May 18, 2020
a573dde
Refactor in prepare_sql (now it returns SQLOperations) and add last o…
Mar 18, 2020
73e99aa
def get_sql in class SQLOperation removed and its calls replaced by .sql
Mar 20, 2020
6c4dfb0
Add @skip_for decorator
kozlovsky May 22, 2020
2ba4d85
Skip test for MySQL: in MySQL BLOB column cannot be part of key witho…
kozlovsky May 22, 2020
23e7d8e
Fix date & datetime processing in MySQL
kozlovsky May 22, 2020
c6b64ad
Remove incorrect test
kozlovsky May 22, 2020
5a535b3
Use LIKE BINARY instead of LIKE in MySQL to get case-insensitive results
kozlovsky May 22, 2020
47d9e4b
Check provider names in `@only_for` and `@skip_for` decorators
kozlovsky May 23, 2020
0e4b5c0
Fix all tests for MySQL
kozlovsky May 23, 2020
6373af7
forgotten obsolete_names arguments
May 26, 2020
6988a23
Setup modules
Jun 3, 2020
2dfad3d
Adding migrations author
Jun 3, 2020
e54cc83
Replace Name property `provided` to `autogenerated`
kozlovsky Jun 3, 2020
76e4dc3
Fix obsolete autogenerated m2m table names
kozlovsky Jun 3, 2020
32b9e12
Add missed `connection` argument to `schema.prepare_sql` method
kozlovsky Jun 3, 2020
b5b0e8a
Fix schema.upgrade() for PostgreSQL: fix obsolete names of m2m tables…
kozlovsky Jun 4, 2020
ce8b6ee
Rename local variable with constraint: con -> cons (to distinguish fr…
kozlovsky Jun 4, 2020
ab15943
Fix
kozlovsky Jun 4, 2020
cde2fd9
Created test database, minor changes in migrations/dbschema.py for ge…
Jun 18, 2020
ea613d1
Added test add entity.
Jun 18, 2020
2905243
Added test add inherited entity
Jun 18, 2020
89fc296
Added test rename entity
Jun 18, 2020
2b23ac9
Added test delete entity
Jun 18, 2020
2cdd2fe
Added test delete inherited entity
Jun 18, 2020
846c359
Added test set any table name
Jun 18, 2020
479e3f6
Added test add required attribute
Jun 18, 2020
8211db4
Added test add optional attribute
Jun 18, 2020
763e868
Added test change attribute name
Jun 18, 2020
3a7ae6a
Added test change string parameter max length
Jun 18, 2020
1671d4b
Added test change int size parameter for integer attribute
Jun 18, 2020
e3ccda6
Added test unset nullable attribute
Jun 18, 2020
3f91e5c
Added test set nullable attribute
Jun 18, 2020
e51a27d
Added test delete attribute
Jun 18, 2020
09d060d
Added test set unique constraint to attribute
Jun 18, 2020
a2e5c47
Added test unset unique constraint to attribute
Jun 18, 2020
2557260
Added test set unsigned constraint to attribute
Jun 18, 2020
3d80659
Adding unsigned constraint to lab_hours attribute in setUp method and…
Jun 18, 2020
4adea59
Added test unset unsigned attribute
Jun 18, 2020
0690bba
Added test set default parameter to attribute
Jun 18, 2020
3bde944
Added test set database column
Jun 18, 2020
cf317f2
Added test set sql type
Jun 18, 2020
938ee81
Added test set sql_default value
Jun 18, 2020
cdf5441
Adding field "rating" to entity "Department"
Jun 18, 2020
8c2abfc
Added test set precision
Jun 18, 2020
3dd98ed
Added test change relation class from required to optional
Jun 19, 2020
2850744
Adding attributes for test
Jun 19, 2020
7e6299f
Added test change relation class from optional to required
Jun 19, 2020
6ab4bb2
Adding attribute last_update for set_precision test, fixes in delete …
Jun 19, 2020
24fd8a3
Changed precision in datetime field in set_precision test
Jun 19, 2020
167129b
Migration fixes
kozlovsky Jun 25, 2020
fe3ef63
Adding opt-opt relation between Teacher and DeptDirector entities.
Jun 22, 2020
2d4cf87
fixes
kozlovsky Jun 26, 2020
aefaead
Fix in "change optional attribute to required in relation" test
Jun 22, 2020
5417159
Fix precision tests
kozlovsky Jun 29, 2020
42293e5
Type casting test moved to test_type_cast.py
Jun 26, 2020
e37efc0
Change db connection parameters in test_type_cast.py
Jun 26, 2020
b95291f
Added type casting test str -> bytes
Jun 26, 2020
d20c0a6
Added type casting test str -> LongStr
Jun 26, 2020
a25f7de
Added type casting test str -> uuid
Jun 26, 2020
c683562
Added type casting test str -> json
Jun 26, 2020
bb32b4c
Fix type cast in postgres
kozlovsky Jun 29, 2020
3826684
Added type casting test int -> str
Jun 29, 2020
dbdd584
Added type casting test int -> float
Jun 29, 2020
744de90
Added type casting test int -> decimal
Jun 29, 2020
75cd8a1
Added type casting test int -> bool
Jun 29, 2020
0821ce3
Added type casting test int -> longstr
Jun 29, 2020
a6d6899
Added type casting test float -> str
Jun 29, 2020
179901f
Added type casting test float -> int
Jun 29, 2020
9aac551
Added type casting test float -> decimal
Jun 29, 2020
d059536
Fixed str -> float test
Jun 29, 2020
b92fdf2
Fixed str -> decimal test
Jun 29, 2020
aef734f
Fixed str -> datetime test
Jun 29, 2020
9b28cf0
Fixed str -> date test
Jun 29, 2020
e58403e
Fixed str -> time test
Jun 29, 2020
5aab8c9
Fixed str -> timedelta test
Jun 29, 2020
922dfa1
Fixed str -> bool test
Jun 29, 2020
1b51b73
Fixed str -> bytes test
Jun 29, 2020
de0aec3
Fixed str -> longstr test
Jun 29, 2020
17068fb
Fixed str -> uuid test
Jun 29, 2020
f110fb9
Fixed str -> json test
Jun 29, 2020
51e842d
Fixed int -> str test
Jun 29, 2020
e1b44cb
Fixed int -> float test
Jun 29, 2020
9f18c12
Fixed int -> decimal test
Jun 29, 2020
50dd044
Fixed int -> bool test
Jun 29, 2020
737854e
Fixed int -> longstr test
Jun 29, 2020
46dd7d6
Fixed float -> str test
Jun 29, 2020
8e8c7d8
Fixed float -> int test
Jun 29, 2020
614ed34
Fixed float -> int test
Jun 29, 2020
ceb8a50
Fixed float -> bool test
Jun 29, 2020
25c0da0
Fixed float -> longstr test
Jun 29, 2020
f57d3a1
Changed asserts order, migrations operations check before generated S…
Jun 29, 2020
dd412e6
Added type casting test decimal -> str
Jun 29, 2020
8a0c848
Added type casting test decimal -> int
Jun 29, 2020
5c2a311
Added type casting test decimal -> float
Jun 29, 2020
adf8b04
Added type casting test decimal -> bool
Jun 29, 2020
012d19a
Added type casting test decimal -> longstr
Jun 29, 2020
52557b5
Added type casting test datetime -> str
Jun 29, 2020
b2eaa51
Added type casting test datetime -> date
Jun 29, 2020
cb2f51f
Added type casting test datetime -> time
Jun 29, 2020
31e6048
Added type casting test datetime -> longstr
Jun 29, 2020
2e6a48f
Added type casting test date -> str
Jun 29, 2020
b2af3ad
Added type casting test date -> datetime
Jun 29, 2020
50e5f93
Added type casting test date -> longstr
Jun 29, 2020
ea36d80
Added type casting test time -> str
Jun 29, 2020
3bcaf63
Added type casting test time -> timedelta
Jun 29, 2020
73f1325
Added type casting test time -> longstr
Jun 29, 2020
8d6e790
Added type casting test timedelta -> str
Jun 29, 2020
297a4c3
Added type casting test timedelta -> time
Jun 29, 2020
3c8adee
Added type casting test timedelta -> longstr
Jun 29, 2020
9f5b215
Added type casting test bool -> str
Jun 29, 2020
6d3ebdf
Added type casting test bool -> int
Jun 29, 2020
2a5251f
Added type casting test bool -> float
Jun 29, 2020
7371396
Added type casting test bool -> decimal
Jun 29, 2020
fe76b91
Added type casting test bool -> longstr
Jun 29, 2020
efec7be
Added type casting test bytes -> str
Jun 29, 2020
bb05b36
Added type casting test bytes -> longstr
Jun 29, 2020
283080d
Added type casting test longstr -> str
Jun 29, 2020
90e0bc4
Added type casting test longstr -> int
Jun 29, 2020
1dadc73
Added type casting test longstr -> float
Jun 29, 2020
c31f621
Added type casting test longstr -> decimal
Jun 29, 2020
fb4d498
Added type casting test longstr -> datetime
Jun 29, 2020
dd735b6
Added type casting test longstr -> date
Jun 29, 2020
dc635bd
Added type casting test longstr -> time
Jun 29, 2020
003cbe4
Added type casting test longstr -> timedelta
Jun 29, 2020
5628581
Added type casting test longstr -> bool
Jun 29, 2020
0cdab00
Added type casting test longstr -> bytes
Jun 29, 2020
f21dd42
Added type casting test longstr -> uuid
Jun 29, 2020
2ca61d1
Added type casting test longstr -> json
Jun 29, 2020
7e2bf23
Added type casting test uuid -> str
Jun 29, 2020
b4a30e8
Added type casting test uuid -> longstr
Jun 29, 2020
0dee1ca
Added type casting test json -> str
Jun 29, 2020
360a230
Added type casting test json -> longstr
Jun 29, 2020
45888b3
Fixed test_change_rel_attr_opt_to_req test
Jun 30, 2020
faa0129
Added test change primary key to required
Jun 30, 2020
61d5823
Added test change primary key to optional
Jun 30, 2020
e62a750
Added test change required to optional
Jun 30, 2020
d861d33
Added test change required to primary key
Jun 30, 2020
1cb9b35
Added test change optional to required
Jun 30, 2020
c336434
Added test change optional to primary key
Jun 30, 2020
c5e4f3f
Change asserts order in new tests
Jun 30, 2020
40173be
Added test "set inherits from entity"
Jun 30, 2020
37478ea
Serialize migrations before apply in tests
kozlovsky Jul 3, 2020
20be433
Use MigrationError and MappingError for all exceptions related to mig…
kozlovsky Jul 6, 2020
8a4faab
Fix migration imports
kozlovsky Jul 7, 2020
dbb90e8
Renaming: without_reverse=True -> with_reverse=False
kozlovsky Jul 7, 2020
c20d34c
Get rid of full_reverse
kozlovsky Jul 7, 2020
747d4f5
Fix adding new entity
kozlovsky Jul 7, 2020
f35580a
Fix delete_inherited_entity
kozlovsky Jul 9, 2020
accfa4b
Fix unset_nullable_attr
kozlovsky Jul 13, 2020
6eea93b
Fix set_unsigned_attr
kozlovsky Jul 14, 2020
5701857
Add test_unset_unsigned_attr_2
kozlovsky Jul 14, 2020
df136cf
Add test_change_optional_to_required_no_initial
kozlovsky Jul 14, 2020
e13b6bc
Use proper way to build UPDATE query
kozlovsky Jul 17, 2020
636ae8d
Fix changing optional attribute to required
kozlovsky Aug 6, 2020
6958c49
Update sqlite.py
sashaaero Sep 9, 2020
a82487f
Fix incorrect m2m table name
sashaaero Jan 20, 2021
af73bcd
Removed restriction on initial parameter
Apr 27, 2021
f7866e1
Fix: adding two entities with relation between them
Apr 29, 2021
8f9484a
Fix bunch of tests improving sql_op decorator
May 7, 2021
a9382bc
Added schema_diff function to find what's the difference between schemas
May 7, 2021
c556433
Added schema_diff function to find what's the difference between schemas
May 7, 2021
c52ae3f
Added schema_diff function to find what's the difference between schemas
May 7, 2021
ff52e55
Fix fix_obsolete_table
May 7, 2021
760d040
Remove unused line
May 7, 2021
91310a6
Fixed adding optional json
May 11, 2021
374bf51
tests added
kozlovsky Aug 13, 2020
54caeab
fixed test_unset_unsigned_attr2 and test_unset_scale
May 13, 2021
44cd607
fixed test_set_scale and test_set_time_precision
May 13, 2021
79d446b
fixed tests
May 13, 2021
fce171e
Fixed adding optional json
May 13, 2021
d3472eb
Adding RemoveRelation operation
May 13, 2021
71949dc
Fix drop index
May 14, 2021
28d3925
Fix test add_relation_opt_to_req
May 14, 2021
928cd72
Fix test
May 14, 2021
8428606
Replaced expected and actual migration_op and correct_sql in assertEq…
May 14, 2021
e4f79bd
Fix test
May 14, 2021
2a01aa9
Fix test
May 14, 2021
d468083
Changes by ivan_zhitnikov
May 14, 2021
4aa6eb0
Fix test
May 14, 2021
c61c935
Changes by ivan_zhitnikov
May 14, 2021
c59e39f
Fix test
May 14, 2021
e9cd2f4
Changes by ivan_zhitnikov
May 14, 2021
2f90312
Fix test
May 14, 2021
094340c
Changes by ivan_zhitnikov
May 14, 2021
edf226c
Fix test
May 14, 2021
3bb2d3e
Fix test
May 14, 2021
b10ab5c
Changes by ivan_zhitnikov
May 14, 2021
60b3917
Remove upgrade and restrict providers other than postgres
May 14, 2021
f3c1107
FIX: nullable str did produce default value
sashaaero May 27, 2021
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion pony/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import os, sys
from os.path import dirname

__version__ = '0.7.15-dev'
__version__ = '0.9.0-dev'

def detect_mode():
try: import google.appengine
Expand Down
267 changes: 221 additions & 46 deletions pony/orm/core.py

Large diffs are not rendered by default.

103 changes: 94 additions & 9 deletions pony/orm/dbapiprovider.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,15 @@
import os, re, json
from decimal import Decimal, InvalidOperation
from datetime import datetime, date, time, timedelta
from time import strptime
from uuid import uuid4, UUID
from hashlib import md5

import pony
from pony.utils import is_utf8, decorator, throw, localbase, deprecated
from pony.converting import str2date, str2time, str2datetime, str2timedelta
from pony.orm.ormtypes import LongStr, LongUnicode, RawSQLType, TrackedValue, TrackedArray, Json, QueryType, Array
# from pony.orm.migrations.operations import *

class DBException(Exception):
def __init__(exc, original_exc, *args):
Expand Down Expand Up @@ -97,6 +100,32 @@ def get_version_tuple(s):
return tuple(int(component) for component in components)
return None

class Name(unicode):
__slots__ = ['obsolete_name', 'autogenerated']

def __new__(cls, name, obsolete_name=None, autogenerated=True):
result = unicode.__new__(cls, name)
result.obsolete_name = obsolete_name
result.autogenerated = autogenerated
return result

def lower(self):
obs_name = self.obsolete_name.lower()
name = str(self).lower()
return Name(name, obs_name)

def upper(self):
obs_name = self.obsolete_name.upper()
name = str(self).upper()
return Name(name, obs_name)


def obsolete(name):
if isinstance(name, tuple):
return name[0], getattr(name[1], 'obsolete_name', name[1])
return getattr(name, 'obsolete_name', name)


class DBAPIProvider(object):
paramstyle = 'qmark'
quote_char = '"'
Expand All @@ -117,11 +146,17 @@ class DBAPIProvider(object):
sqlbuilder_cls = None
array_converter_cls = None

purge_template = None

cast_sql = None

name_before_table = 'schema_name'
default_schema_name = None

fk_types = { 'SERIAL' : 'INTEGER', 'BIGSERIAL' : 'BIGINT' }

implicit_fk_indexes = False

def __init__(provider, *args, **kwargs):
pool_mockup = kwargs.pop('pony_pool_mockup', None)
call_on_connect = kwargs.pop('pony_call_on_connect', None)
Expand All @@ -137,8 +172,23 @@ def __init__(provider, *args, **kwargs):
def inspect_connection(provider, connection):
pass

# def normalize_name(provider, name):
# return name[:provider.max_name_len]

def normalize_case_name(provider, name):
return name

def normalize_name(provider, name):
return name[:provider.max_name_len]
name = provider.normalize_case_name(name)
obsolete_name = obsolete(name)
max_len = provider.max_name_len
if len(name) > max_len:
hash = md5(name.encode('utf-8')).hexdigest()[:8]
normalized_name = '%s_%s' % (name[:max_len - 9], hash)
else:
normalized_name = name
normalized_obsolete_name = obsolete_name[:max_len]
return Name(normalized_name, obsolete_name=normalized_obsolete_name)

def get_default_entity_table_name(provider, entity):
return provider.normalize_name(entity.__name__)
Expand Down Expand Up @@ -207,6 +257,8 @@ def quote_name(provider, name):
if isinstance(name, basestring):
name = name.replace(quote_char, quote_char+quote_char)
return quote_char + name + quote_char
if name is None:
assert False
return '.'.join(provider.quote_name(item) for item in name)

def format_table_name(provider, name):
Expand Down Expand Up @@ -331,6 +383,9 @@ def drop_table(provider, connection, table_name):
sql = 'DROP TABLE %s' % provider.quote_name(table_name)
cursor.execute(sql)

def purge(provider, connection, schemas):
raise NotImplementedError

class Pool(localbase):
forked_connections = []
def __init__(pool, dbapi_module, *args, **kwargs): # called separately in each thread
Expand Down Expand Up @@ -387,6 +442,13 @@ def __init__(converter, provider, py_type, attr=None):
def init(converter, kwargs):
attr = converter.attr
if attr and attr.args: unexpected_args(attr, attr.args)
def make_fk_converter(converter, attr):
if not attr.sql_type and converter.attr.sql_type:
attr.sql_type = converter.get_fk_type(converter.attr.sql_type)
new_converter = converter.__class__(converter.provider, converter.py_type)
new_converter.__dict__.update(converter.__dict__)
new_converter.attr = attr
return new_converter
def validate(converter, val, obj=None):
return val
def py2sql(converter, val):
Expand All @@ -399,6 +461,8 @@ def dbval2val(self, dbval, obj=None):
return dbval
def dbvals_equal(self, x, y):
return x == y
def sql_type(converter):
return None
def get_sql_type(converter, attr=None):
if attr is not None and attr.sql_type is not None:
return attr.sql_type
Expand Down Expand Up @@ -455,7 +519,11 @@ def init(converter, kwargs):
elif max_len is None: max_len = converter.provider.varchar_default_max_len
elif not isinstance(max_len, int_types):
throw(TypeError, 'Max length argument must be int. Got: %r' % max_len)

converter.max_len = max_len
if converter.attr.provided.args:
converter.attr.provided.kwargs['max_len'] = max_len
converter.attr.provided.args = []
converter.db_encoding = kwargs.pop('db_encoding', None)
converter.autostrip = kwargs.pop('autostrip', True)
def validate(converter, val, obj=None):
Expand Down Expand Up @@ -514,7 +582,7 @@ def init(converter, kwargs):
if unsigned is not None and size is None: size = 32
lowest = highest = None
if size:
highest = highest = 2 ** size - 1 if unsigned else 2 ** (size - 1) - 1
highest = 2 ** size - 1 if unsigned else 2 ** (size - 1) - 1
lowest = 0 if unsigned else -(2 ** (size - 1))

if highest is not None and max_val is not None and max_val > highest:
Expand All @@ -525,6 +593,7 @@ def init(converter, kwargs):
throw(ValueError, "'min' argument should be greater or equal to %d because of size=%d and unsigned=%s. "
"Got: %d" % (lowest, size, min_val, unsigned))


converter.min_val = min_val or lowest
converter.max_val = max_val or highest
converter.size = size
Expand Down Expand Up @@ -625,8 +694,16 @@ def init(converter, kwargs):
"'scale' positional argument for attribute %s must be positive. Got: %r" % (attr, scale))

if scale > precision: throw(ValueError, "'scale' must be less or equal 'precision'")
attr_kwargs = converter.attr.provided.kwargs
attr_args = converter.attr.provided.args
converter.precision = precision
converter.scale = scale
if len(attr_args) >= 1:
attr_kwargs['precision'] = precision
if len(attr_args) == 2:
attr_kwargs['scale'] = scale
converter.attr.provided.args = []
converter.attr.provided.args = []
converter.exp = Decimal(10) ** -scale

min_val = kwargs.pop('min', None)
Expand Down Expand Up @@ -672,7 +749,7 @@ def sql2py(converter, val):
if not isinstance(val, buffer):
try: val = buffer(val)
except: pass
elif PY2 and converter.attr is not None and converter.attr.is_part_of_unique_index:
elif PY2 and converter.attr is not None and converter.attr.real_attr.is_part_of_unique_index:
try: hash(val)
except TypeError:
val = buffer(val)
Expand All @@ -687,8 +764,10 @@ def validate(converter, val, obj=None):
if isinstance(val, basestring): return str2date(val)
throw(TypeError, "Attribute %r: expected type is 'date'. Got: %r" % (converter.attr, val))
def sql2py(converter, val):
if not isinstance(val, date): throw(ValueError,
'Value of unexpected type received from database: instead of date got %s' % type(val))
if isinstance(val, str):
val = str2datetime(val).date
elif not isinstance(val, date):
throw(ValueError, 'Value of unexpected type received from database: instead of date got %s' % type(val))
return val
def sql_type(converter):
return 'DATE'
Expand All @@ -702,7 +781,8 @@ def init(converter, kwargs):
args = attr.args
if len(args) > 1: throw(TypeError, 'Too many positional parameters for attribute %s. '
'Expected: precision, got: %r' % (attr, args))
provider = attr.entity._database_.provider
provider = attr.entity.db.provider

if args:
precision = args[0]
if 'precision' in kwargs: throw(TypeError,
Expand All @@ -714,6 +794,9 @@ def init(converter, kwargs):
'Precision value (%d) of attribute %s exceeds max datetime precision (%d) of %s %s'
% (precision, attr, provider.max_time_precision, provider.dialect, provider.server_version))
converter.precision = precision
if converter.attr.provided.args:
converter.attr.provided.kwargs['precision'] = precision
converter.attr.provided.args = []
def round_microseconds_to_precision(converter, microseconds, precision):
# returns None if no change is required
if not precision: result = 0
Expand All @@ -725,7 +808,7 @@ def round_microseconds_to_precision(converter, microseconds, precision):
def sql_type(converter):
attr = converter.attr
precision = converter.precision
if not attr or precision == attr.entity._database_.provider.default_time_precision:
if not attr or precision == attr.entity.db.schema.provider.default_time_precision:
return converter.sql_type_name
return converter.sql_type_name + '(%d)' % precision

Expand Down Expand Up @@ -767,8 +850,10 @@ def validate(converter, val, obj=None):
if mcs is not None: val = val.replace(microsecond=mcs)
return val
def sql2py(converter, val):
if not isinstance(val, datetime): throw(ValueError,
'Value of unexpected type received from database: instead of datetime got %s' % type(val))
if isinstance(val, str):
val = str2datetime(val)
elif not isinstance(val, datetime):
throw(ValueError, 'Value of unexpected type received from database: instead of datetime got %s' % type(val))
return val

class UuidConverter(Converter):
Expand Down
Loading