Skip to content

Commit

Permalink
Performance tuning (#51)
Browse files Browse the repository at this point in the history
* __init__ restructure give 25-30% speedup in select benchmark.

I also cleared up a few lint warnings.

* Fix check

* v0.10.8

* Fix bad refactor

* Allow NPE to pass through
  • Loading branch information
grigi authored and abondar committed Sep 28, 2018
1 parent 7eaf937 commit 2010833
Show file tree
Hide file tree
Showing 13 changed files with 60 additions and 57 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
Changelog
=========

0.10.8
------
- Performance fixes from ``pypika`` and object retrieval

0.10.7
------
- Fixed SQLite relative db path and :memory: now also works
Expand Down
6 changes: 3 additions & 3 deletions requirements-dev.txt
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ certifi==2018.8.24 # via requests
cffi==1.11.5 # via cryptography
chardet==3.0.4 # via requests
ciso8601==2.0.1
click==6.7 # via pip-tools
click==7.0 # via pip-tools
cloud-sptheme==1.9.4
colorama==0.3.9 # via green
coverage==4.5.1 # via coveralls, green
Expand All @@ -41,7 +41,7 @@ markupsafe==1.0 # via jinja2
mccabe==0.6.1 # via flake8, pylint
mypy-extensions==0.4.1 # via mypy
mypy==0.630
packaging==17.1 # via sphinx
packaging==18.0 # via sphinx
pbr==4.2.0 # via stevedore
pip-tools==3.0.0
pluggy==0.7.1 # via tox
Expand All @@ -53,7 +53,7 @@ pygments==2.2.0
pylint==2.1.1
pymysql==0.9.2 # via aiomysql
pyparsing==2.2.1 # via packaging
pypika==0.15.5
pypika==0.15.6
pytz==2018.5 # via babel
pyyaml==3.13 # via bandit
requests==2.19.1 # via coveralls, sphinx
Expand Down
2 changes: 1 addition & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
pypika>=0.15.4,<1.0
pypika>=0.15.6,<1.0
ciso8601>=2.0
aiocontextvars==0.1.2;python_version<"3.7"
aiosqlite>=0.6.0
2 changes: 1 addition & 1 deletion tortoise/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -374,4 +374,4 @@ async def do_stuff():
loop.run_until_complete(Tortoise.close_connections())


__version__ = "0.10.7"
__version__ = "0.10.8"
7 changes: 4 additions & 3 deletions tortoise/backends/asyncpg/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ class AsyncpgDBClient(BaseDBAsyncClient):
executor_class = AsyncpgExecutor
schema_generator = AsyncpgSchemaGenerator

def __init__(self, user, password, database, host, port, *args, **kwargs):
super().__init__(*args, **kwargs)
def __init__(self, user, password, database, host, port, **kwargs):
super().__init__(**kwargs)

self.user = user
self.password = password
Expand Down Expand Up @@ -107,7 +107,7 @@ def _in_transaction(self):
else:
return self._transaction_class(self.connection_name, pool=self._db_pool)

async def execute_query(self, query):
async def execute_query(self, query, get_inserted_id=False):
try:
async with self.acquire_connection() as connection:
self.log.debug(query)
Expand Down Expand Up @@ -153,6 +153,7 @@ def __init__(self, connection_name, pool=None, connection=None):
self._transaction_class = self.__class__
self._old_context_value = None
self.connection_name = connection_name
self.transaction = None

def acquire_connection(self):
return ConnectionWrapper(self._connection)
Expand Down
6 changes: 4 additions & 2 deletions tortoise/backends/base/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ def acquire_connection(self):
def _in_transaction(self):
raise NotImplementedError() # pragma: nocoverage

async def execute_query(self, query):
async def execute_query(self, query, get_inserted_id=False):
raise NotImplementedError() # pragma: nocoverage

async def execute_script(self, script):
Expand All @@ -62,10 +62,12 @@ async def __aexit__(self, exc_type, exc_val, exc_tb):


class SingleConnectionWrapper(BaseDBAsyncClient):
# pylint: disable=W0223,W0231

def __init__(self, connection_name, connection, closing_callback=None):
self.log = logging.getLogger('db_client')
self.connection_name = connection_name
self.connection = connection
self.log = logging.getLogger('db_client')
self.single_connection = True
self.closing_callback = closing_callback

Expand Down
28 changes: 14 additions & 14 deletions tortoise/backends/base/config_generator.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
DB_LOOKUP = {
'postgres': {
'engine': 'tortoise.backends.asyncpg',
'vars': {
'vmap': {
'path': 'database',
'hostname': 'host',
'port': 'port',
Expand All @@ -21,13 +21,13 @@
'sqlite': {
'engine': 'tortoise.backends.sqlite',
'skip_first_char': False,
'vars': {
'vmap': {
'path': 'file_path',
},
},
'mysql': {
'engine': 'tortoise.backends.mysql',
'vars': {
'vmap': {
'path': 'database',
'hostname': 'host',
'port': 'port',
Expand Down Expand Up @@ -61,20 +61,20 @@ def expand_db_url(db_url: str, testing: bool = False) -> dict:
path = path.replace('\\{', '{').replace('\\}', '}')
path = path.format(uuid.uuid4().hex)

vars = {} # type: dict
vars.update(db['vars'])
params[vars['path']] = path
if vars.get('hostname'):
params[vars['hostname']] = str(url.hostname or '')
vmap = {} # type: dict
vmap.update(db['vmap'])
params[vmap['path']] = path
if vmap.get('hostname'):
params[vmap['hostname']] = str(url.hostname or '')
try:
if vars.get('port'):
params[vars['port']] = str(url.port or '')
if vmap.get('port'):
params[vmap['port']] = str(url.port or '')
except ValueError:
raise ConfigurationError('Port is not an integer')
if vars.get('username'):
params[vars['username']] = str(url.username or '')
if vars.get('password'):
params[vars['password']] = str(url.password or '')
if vmap.get('username'):
params[vmap['username']] = str(url.username or '')
if vmap.get('password'):
params[vmap['password']] = str(url.password or '')

return {
'engine': db['engine'],
Expand Down
3 changes: 0 additions & 3 deletions tortoise/backends/base/schema_generator.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,6 @@ def _get_primary_key_create_string(self, field_name):
# has to implement in children
raise NotImplementedError() # pragma: nocoverage

def _get_auto_now_add_default(self):
raise NotImplementedError() # pragma: nocoverage

def _get_table_sql(self, model) -> dict:
fields_to_create = []
m2m_tables_for_create = []
Expand Down
4 changes: 2 additions & 2 deletions tortoise/backends/mysql/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ class MySQLClient(BaseDBAsyncClient):
executor_class = MySQLExecutor
schema_generator = MySQLSchemaGenerator

def __init__(self, user, password, database, host, port, *args, **kwargs):
super().__init__(*args, **kwargs)
def __init__(self, user, password, database, host, port, **kwargs):
super().__init__(**kwargs)

self.user = user
self.password = password
Expand Down
4 changes: 2 additions & 2 deletions tortoise/backends/sqlite/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ class SqliteClient(BaseDBAsyncClient):
executor_class = SqliteExecutor
schema_generator = SqliteSchemaGenerator

def __init__(self, file_path, *args, **kwargs):
super().__init__(*args, **kwargs)
def __init__(self, file_path, **kwargs):
super().__init__(**kwargs)
self.filename = file_path
self._transaction_class = type(
'TransactionWrapper', (TransactionWrapper, self.__class__), {}
Expand Down
4 changes: 2 additions & 2 deletions tortoise/fields.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ class Field:
"""
def __init__(
self,
type=None,
type=None, # pylint: disable=W0622
source_field: Optional[str] = None,
generated: bool = False,
pk: bool = False,
Expand Down Expand Up @@ -301,7 +301,7 @@ def __init__(


class BackwardFKRelation:
def __init__(self, type, relation_field, **kwargs):
def __init__(self, type, relation_field, **kwargs): # pylint: disable=W0622
self.type = type
self.relation_field = relation_field

Expand Down
42 changes: 19 additions & 23 deletions tortoise/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -328,21 +328,17 @@ class Model(metaclass=ModelMeta):

def __init__(self, *args, **kwargs) -> None:
is_new = not bool(kwargs.get('id'))
passed_fields = set(kwargs.keys())

for key, field in self._meta.fields_map.items():
if isinstance(field, fields.BackwardFKRelation):
setattr(
self, key,
RelationQueryContainer(field.type, field.relation_field, self, is_new)
)
elif isinstance(field, fields.ManyToManyField):
setattr(self, key, ManyToManyRelationManager(field.type, self, field, is_new))
elif isinstance(field, fields.Field):
setattr(self, key, field.default)
else:
setattr(self, key, None)
for key in self._meta.backward_fk_fields:
field = self._meta.fields_map[key]
setattr(self, key, RelationQueryContainer(
field.type, field.relation_field, self, is_new)) # type: ignore

for key in self._meta.m2m_fields:
field = self._meta.fields_map[key]
setattr(self, key, ManyToManyRelationManager(field.type, self, field, is_new))

passed_fields = set(kwargs.keys())
for key, value in kwargs.items():
if key in self._meta.fk_fields:
if hasattr(value, 'id') and not value.id:
Expand All @@ -351,6 +347,13 @@ def __init__(self, *args, **kwargs) -> None:
relation_field = '{}_id'.format(key)
setattr(self, relation_field, value.id)
passed_fields.add(relation_field)
elif key in self._meta.fields:
field_object = self._meta.fields_map[key]
if value is None and not field_object.null:
raise ValueError('{} is non nullable field, but null was passed'.format(key))
setattr(self, key, field_object.to_python_value(value))
elif key in self._meta.db_fields:
setattr(self, self._meta.fields_db_projection_reverse[key], value)
elif key in self._meta.backward_fk_fields:
raise ConfigurationError(
'You can\'t set backward relations through init, change related model instead'
Expand All @@ -359,18 +362,11 @@ def __init__(self, *args, **kwargs) -> None:
raise ConfigurationError(
'You can\'t set m2m relations through init, use m2m_manager instead'
)
elif key in self._meta.fields:
field_object = self._meta.fields_map[key]
if value is None and not field_object.null:
raise ValueError('{} is non nullable field, but null was passed'.format(key))
setattr(self, key, field_object.to_python_value(value))
elif key in self._meta.db_fields:
setattr(self, self._meta.fields_db_projection_reverse[key], value)

passed_fields.update(self._meta.fetch_fields)

for key, field_object in self._meta.fields_map.items():
if key in passed_fields or key in self._meta.fetch_fields:
continue
else:
if key not in passed_fields:
if callable(field_object.default):
setattr(self, key, field_object.default())
else:
Expand Down
4 changes: 3 additions & 1 deletion tortoise/queryset.py
Original file line number Diff line number Diff line change
Expand Up @@ -284,7 +284,7 @@ def annotate(self, **kwargs) -> 'QuerySet':
queryset._available_custom_filters.update(get_filters_for_field(key, None, key))
return queryset

def values_list(self, *fields: str, flat: bool = False):
def values_list(self, *fields: str, flat: bool = False): # pylint: disable=W0621
"""
Make QuerySet returns list of tuples for given args instead of objects.
If ```flat=True`` and only one arg is passed can return flat list.
Expand Down Expand Up @@ -581,6 +581,8 @@ async def _execute(self):


class FieldSelectQuery(AwaitableQuery):
# pylint: disable=W0223

def _join_table_with_forwarded_fields(self, model, field, forwarded_fields):
table = Table(model._meta.table)
if field in model._meta.fields_db_projection and not forwarded_fields:
Expand Down

0 comments on commit 2010833

Please sign in to comment.