Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
6 changes: 0 additions & 6 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,6 @@ jobs:
container:
- image: python:latest
toxenv: lint
- image: python:3.6
toxenv: py36-sqla12
- image: python:3.6
toxenv: py36-sqla13
- image: python:3.6
toxenv: py36-sqla14
- image: python:3.7
toxenv: py37-sqla12
- image: python:3.7
Expand Down
22 changes: 11 additions & 11 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -1,34 +1,34 @@
---
repos:

- repo: https://github.com/miki725/importanize
rev: '0.7'
hooks:
- id: importanize
language_version: python3

- repo: https://github.com/psf/black
rev: 22.6.0
hooks:
- id: black
language_version: python3


- repo: https://github.com/pycqa/isort
rev: 5.10.1
hooks:
- id: isort
name: isort (python)

- repo: https://github.com/asottile/pyupgrade
rev: v2.37.3
hooks:
- id: pyupgrade
args: [--py3-plus]

- repo: https://github.com/myint/docformatter
rev: v1.4
rev: v1.5.0-rc1
hooks:
- id: docformatter

- repo: https://github.com/PyCQA/flake8
rev: 5.0.2
- repo: https://github.com/flakeheaven/flakeheaven
rev: 3.0.0
hooks:
- id: flake8
exclude: deployment/roles
- id: flakeheaven
additional_dependencies:
- flake8-bugbear
- flake8-comprehensions
Expand Down
2 changes: 0 additions & 2 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,11 @@ USER sorcerer
ENV PATH=/opt/pyenv/bin:/home/sorcerer/.pyenv/shims:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
WORKDIR /code

RUN pyenv install 3.6:latest
RUN pyenv install 3.7:latest
RUN pyenv install 3.8:latest
RUN pyenv install 3.9:latest
RUN pyenv install 3.10:latest

RUN pyenv install pypy3.6:latest
RUN pyenv install pypy3.7:latest
RUN pyenv install pypy3.8:latest

Expand Down
1 change: 0 additions & 1 deletion MANIFEST.in
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ include *.txt
include *.yaml *.yml
include LICENSE
include Makefile
include pytest.ini
include tox.ini
include Dockerfile
exclude .*
Expand Down
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ next: # print next version
@echo $(NEXT)

bump: history
@sed -i 's/$(VERSION)/$(NEXT)/g' $(PACKAGE)/__version__.py
@sed -i 's/$(VERSION)/$(NEXT)/g' $(PACKAGE)/__init__.py
@sed -i 's/Next version (unreleased yet)/$(NEXT) ($(shell date +"%Y-%m-%d"))/g' HISTORY.rst
@git add .
@git commit -am "Bump version: $(VERSION) → $(NEXT)"
Expand Down
15 changes: 2 additions & 13 deletions django_sorcery/__init__.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,3 @@
from .__version__ import (
__author__,
__author_email__,
__description__,
__version__,
)
__version__ = "0.12.0"


__all__ = [
"__author__",
"__author_email__",
"__description__",
"__version__",
]
VERSION = tuple(__version__.split("."))
4 changes: 0 additions & 4 deletions django_sorcery/__version__.py

This file was deleted.

1 change: 0 additions & 1 deletion django_sorcery/db/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -141,5 +141,4 @@
from .sqlalchemy import SQLAlchemy # noqa
from .utils import dbdict


databases = dbdict()
11 changes: 5 additions & 6 deletions django_sorcery/db/fields.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@

from .url import DIALECT_MAP_TO_DJANGO


__all__ = [
"BigIntegerField",
"BinaryField",
Expand Down Expand Up @@ -46,11 +45,8 @@ class Field(sa.Column):
def __init__(self, *args, **kwargs):
self.db = kwargs.pop("db", None)

name = None
args = list(args)
if args and isinstance(args[0], str):
name = args.pop(0)

name = args.pop(0) if args and isinstance(args[0], str) else None
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Function Field.__init__ refactored with the following changes:

column_type = kwargs.pop("type_", None)
if args and hasattr(args[0], "_sqla_type"):
column_type = args.pop(0)
Expand Down Expand Up @@ -267,11 +263,14 @@ def get_django_dialect_ranges(self):
ops = operations.BaseDatabaseOperations
with suppress(ImportError):
ops = (
import_string(DIALECT_MAP_TO_DJANGO.get(self.db.url.get_dialect().name) + ".base.DatabaseOperations")
import_string(
f"{DIALECT_MAP_TO_DJANGO.get(self.db.url.get_dialect().name)}.base.DatabaseOperations"
)
if self.db
else operations.BaseDatabaseOperations
)


Comment on lines -270 to +273
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Function ValidateIntegerFieldMixin.get_django_dialect_ranges refactored with the following changes:

return ops.integer_field_ranges

def get_dialect_range(self):
Expand Down
12 changes: 4 additions & 8 deletions django_sorcery/db/meta/column.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
import enum
from contextlib import suppress

import sqlalchemy as sa
from dateutil.parser import parse
import sqlalchemy as sa
from django import forms as djangoforms
from django.conf import settings
from django.core import validators as djangovalidators
Expand Down Expand Up @@ -166,7 +166,7 @@ def clean(self, value, instance):

def validate(self, value, instance):
"""Validate value and raise ValidationError if necessary."""
getattr(instance, "clean_" + self.name, bool)()
getattr(instance, f"clean_{self.name}", bool)()
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Function column_info.validate refactored with the following changes:


def run_validators(self, value):
"""Run field's validators and raise ValidationError if necessary."""
Expand Down Expand Up @@ -194,9 +194,7 @@ def __init__(self, column, prop=None, parent=None, name=None):
self.field_kwargs["max_length"] = self.column.type.length

def to_python(self, value):
if value is None:
return value
return str(value).strip()
return value if value is None else str(value).strip()
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Function string_column_info.to_python refactored with the following changes:



class text_column_info(string_column_info):
Expand Down Expand Up @@ -324,9 +322,7 @@ def to_python(self, value):
return bool(value)
if value in ("t", "T"):
return True
if value in ("f", "F"):
return False
return self.coercer.to_python(value)
return False if value in ("f", "F") else self.coercer.to_python(value)
Comment on lines -327 to +325
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Function boolean_column_info.to_python refactored with the following changes:



class date_column_info(column_info):
Expand Down
30 changes: 17 additions & 13 deletions django_sorcery/db/meta/model.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
"""Metadata for sqlalchemy models."""
from collections import OrderedDict, namedtuple
from collections import OrderedDict
from collections import namedtuple
from functools import partial
from itertools import chain

import inflect
import sqlalchemy as sa
from django.apps import apps
from django.core.exceptions import FieldDoesNotExist, ValidationError
from django.core.exceptions import FieldDoesNotExist
from django.core.exceptions import ValidationError

from ...exceptions import NestedValidationError
from ...validators import ValidationRunner
Expand All @@ -15,7 +17,6 @@
from .composite import composite_info
from .relations import relation_info


Identity = namedtuple("Key", ["model", "pk"])
inflector = inflect.engine()

Expand Down Expand Up @@ -75,8 +76,8 @@ def __init__(self, model):
app_config = apps.get_containing_app_config(self.model_class.__module__)
self.app_label = getattr(app_config, "label", None) or "django_sorcery"

self.label = "{}.{}".format(self.app_label, self.object_name)
self.label_lower = "{}.{}".format(self.app_label, self.model_name)
self.label = f"{self.app_label}.{self.object_name}"
self.label_lower = f"{self.app_label}.{self.model_name}"
Comment on lines -78 to +80
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Function model_info.__init__ refactored with the following changes:


sa.event.listen(self.mapper, "mapper_configured", self._init)
self._init(self.mapper, self.model_class)
Expand Down Expand Up @@ -147,10 +148,16 @@ def __getattr__(self, name):

def __repr__(self):
reprs = ["<model_info({!s})>".format(self.model_class.__name__)]
reprs.extend(" " + repr(i) for i in self.primary_keys.values())
reprs.extend(" " + repr(i) for _, i in sorted(self.properties.items()))
reprs.extend(" " + i for i in chain(*[repr(c).split("\n") for _, c in sorted(self.composites.items())]))
reprs.extend(" " + repr(i) for _, i in sorted(self.relationships.items()))
reprs.extend(f" {repr(i)}" for i in self.primary_keys.values())
reprs.extend(f" {repr(i)}" for _, i in sorted(self.properties.items()))
reprs.extend(
f" {i}"
for i in chain(
*[repr(c).split("\n") for _, c in sorted(self.composites.items())]
)
)

reprs.extend(f" {repr(i)}" for _, i in sorted(self.relationships.items()))
Comment on lines -150 to +160
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Function model_info.__repr__ refactored with the following changes:

return "\n".join(reprs)

@property
Expand Down Expand Up @@ -185,10 +192,7 @@ def primary_keys_from_dict(self, kwargs):
if any(pk is None for pk in pks):
return None

if len(pks) < 2:
return next(iter(pks), None)

return tuple(pks)
return next(iter(pks), None) if len(pks) < 2 else tuple(pks)
Comment on lines -188 to +195
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Function model_info.primary_keys_from_dict refactored with the following changes:


def primary_keys_from_instance(self, instance):
"""Return a dict containing the primary keys of the ``instance``"""
Expand Down
22 changes: 12 additions & 10 deletions django_sorcery/db/meta/relations.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,10 @@ def __init__(self, relationship):
self.local_remote_pairs_for_identity_key = []
try:
# ensure local_remote pairs are of same order as remote pk
for i in target_pk:
self.local_remote_pairs_for_identity_key.append((pairs[i], i))
self.local_remote_pairs_for_identity_key.extend(
(pairs[i], i) for i in target_pk
)

Comment on lines -58 to +61
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Function relation_info.__init__ refactored with the following changes:

except KeyError:
# if relation is missing one of related pk columns
# but actual constraint has it defined
Expand All @@ -78,8 +80,10 @@ def __init__(self, relationship):

if len(matching_constraints) == 1:
pairs = {i.column: i.parent for i in matching_constraints[0].elements}
for i in target_pk:
self.local_remote_pairs_for_identity_key.append((pairs[i], i))
self.local_remote_pairs_for_identity_key.extend(
(pairs[i], i) for i in target_pk
)

else:
# if everything fails, return default pairs
self.local_remote_pairs_for_identity_key = self.local_remote_pairs[:]
Expand All @@ -95,12 +99,10 @@ def formfield(self, form_class=None, **kwargs):
return form_class(self.related_model, **field_kwargs)

def get_form_class(self):
from ...fields import ModelChoiceField, ModelMultipleChoiceField

if self.uselist:
return ModelMultipleChoiceField
from ...fields import ModelChoiceField
from ...fields import ModelMultipleChoiceField

return ModelChoiceField
return ModelMultipleChoiceField if self.uselist else ModelChoiceField

def __repr__(self):
return "<relation_info({}.{})>".format(self.parent_model.__name__, self.name)
return f"<relation_info({self.parent_model.__name__}.{self.name})>"
Comment on lines -106 to +108
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Function relation_info.__repr__ refactored with the following changes:

1 change: 0 additions & 1 deletion django_sorcery/db/middleware.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
from . import databases
from .signals import all_signals


before_middleware_request = all_signals.signal("before_middleware_request")
after_middleware_response = all_signals.signal("after_middleware_response")

Expand Down
12 changes: 7 additions & 5 deletions django_sorcery/db/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,13 @@
import sqlalchemy as sa
import sqlalchemy.ext.declarative # noqa
import sqlalchemy.orm # noqa
from sqlalchemy.orm.base import MANYTOONE
from sqlalchemy.orm.base import NO_VALUE
from django.core.exceptions import ValidationError
from django.utils.text import camel_case_to_spaces
from sqlalchemy.orm.base import MANYTOONE, NO_VALUE

from . import meta, signals
from . import meta
from . import signals
from .mixins import CleanMixin


Expand Down Expand Up @@ -231,9 +233,9 @@ class BaseMeta(sqlalchemy.ext.declarative.DeclarativeMeta):
"""Base metaclass for models which registers models to DB model registry
when models are created."""

def __new__(mcs, name, bases, attrs):
klass = super().__new__(mcs, name, bases, attrs)
mcs.db.models_registry.append(klass)
def __new__(cls, name, bases, attrs):
klass = super().__new__(cls, name, bases, attrs)
cls.db.models_registry.append(klass)
Comment on lines -234 to +238
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Function BaseMeta.__new__ refactored with the following changes:

return klass


Expand Down
13 changes: 8 additions & 5 deletions django_sorcery/db/profiler.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
"""sqlalchemy profiling things."""
import logging
import time
from collections import defaultdict, namedtuple
from collections import defaultdict
from collections import namedtuple
from functools import partial
from threading import local

import sqlalchemy as sa
from django.conf import settings


logger = logging.getLogger(__name__)
STATEMENT_TYPES = {"SELECT": "select", "INSERT INTO": "insert", "UPDATE": "update", "DELETE": "delete"}

Expand Down Expand Up @@ -190,17 +190,20 @@ def process_response(self, request, response):
try:
stats = self.profiler.stats
if stats["duration"] or self.log_results:
self.log(**{"sa_{}".format(k): v for k, v in stats.items()})
self.log(**{f"sa_{k}": v for k, v in stats.items()})
except Exception: # pragma: nocover
# The show must go on...
pass # pragma: nocover
else:
if self.header_results:
for k, v in stats.items():
response["X-SA-{}".format("".join(i.title() for i in k.split("_")))] = v
response[f'X-SA-{"".join(i.title() for i in k.split("_"))}'] = v
Comment on lines -193 to +200
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Function SQLAlchemyProfilingMiddleware.process_response refactored with the following changes:

self.profiler.clear()
return response

def log(self, **kwargs):
"""Log sqlalchemy stats for current request."""
self.logger.info("SQLAlchemy profiler %s", " ".join("{}={}".format(k, v) for k, v in kwargs.items()))
self.logger.info(
"SQLAlchemy profiler %s",
" ".join(f"{k}={v}" for k, v in kwargs.items()),
)
Comment on lines -206 to +209
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Function SQLAlchemyProfilingMiddleware.log refactored with the following changes:

Loading