all: implement black as code formatter

This commit is contained in:
Jens Langhammer
2019-12-31 12:51:16 +01:00
parent 8eb3f0f708
commit 3bd1eadd51
298 changed files with 4825 additions and 3145 deletions

View File

@ -5,6 +5,6 @@ from django.apps import AppConfig
class PassbookLibConfig(AppConfig):
"""passbook lib app config"""
name = 'passbook.lib'
label = 'passbook_lib'
verbose_name = 'passbook lib'
name = "passbook.lib"
label = "passbook_lib"
verbose_name = "passbook lib"

View File

@ -3,7 +3,7 @@ from django.utils.decorators import method_decorator
from django.views.decorators.cache import never_cache
class NeverCacheMixin():
class NeverCacheMixin:
"""Use never_cache as mixin for CBV"""
@method_decorator(never_cache)

View File

@ -11,14 +11,12 @@ from django.conf import ImproperlyConfigured
from django.utils.autoreload import autoreload_started
from structlog import get_logger
SEARCH_PATHS = [
'passbook/lib/default.yml',
'/etc/passbook/config.yml',
'',
] + glob('/etc/passbook/config.d/*.yml', recursive=True)
SEARCH_PATHS = ["passbook/lib/default.yml", "/etc/passbook/config.yml", "",] + glob(
"/etc/passbook/config.d/*.yml", recursive=True
)
LOGGER = get_logger()
ENV_PREFIX = 'PASSBOOK'
ENVIRONMENT = os.getenv(f'{ENV_PREFIX}_ENV', 'local')
ENV_PREFIX = "PASSBOOK"
ENVIRONMENT = os.getenv(f"{ENV_PREFIX}_ENV", "local")
class ConfigLoader:
@ -34,7 +32,7 @@ class ConfigLoader:
def __init__(self):
super().__init__()
base_dir = os.path.realpath(os.path.join(os.path.dirname(__file__), '../..'))
base_dir = os.path.realpath(os.path.join(os.path.dirname(__file__), "../.."))
for path in SEARCH_PATHS:
# Check if path is relative, and if so join with base_dir
if not os.path.isabs(path):
@ -44,8 +42,10 @@ class ConfigLoader:
self.update_from_file(path)
elif os.path.isdir(path) and os.path.exists(path):
# Path is an existing dir, so we try to read the env config from it
env_paths = [os.path.join(path, ENVIRONMENT + '.yml'),
os.path.join(path, ENVIRONMENT + '.env.yml')]
env_paths = [
os.path.join(path, ENVIRONMENT + ".yml"),
os.path.join(path, ENVIRONMENT + ".env.yml"),
]
for env_file in env_paths:
if os.path.isfile(env_file) and os.path.exists(env_file):
# Update config with env file
@ -66,7 +66,7 @@ class ConfigLoader:
def parse_uri(self, value):
"""Parse string values which start with a URI"""
url = urlparse(value)
if url.scheme == 'env':
if url.scheme == "env":
value = os.getenv(url.netloc, url.query)
return value
@ -81,7 +81,7 @@ class ConfigLoader:
except yaml.YAMLError as exc:
raise ImproperlyConfigured from exc
except PermissionError as exc:
LOGGER.warning('Permission denied while reading file', path=path, error=exc)
LOGGER.warning("Permission denied while reading file", path=path, error=exc)
def update_from_dict(self, update: dict):
"""Update config from dict"""
@ -94,10 +94,10 @@ class ConfigLoader:
for key, value in os.environ.items():
if not key.startswith(ENV_PREFIX):
continue
relative_key = key.replace(f"{ENV_PREFIX}_", '').replace('__', '.').lower()
relative_key = key.replace(f"{ENV_PREFIX}_", "").replace("__", ".").lower()
# Recursively convert path from a.b.c into outer[a][b][c]
current_obj = outer
dot_parts = relative_key.split('.')
dot_parts = relative_key.split(".")
for dot_part in dot_parts[:-1]:
if dot_part not in current_obj:
current_obj[dot_part] = {}
@ -122,7 +122,7 @@ class ConfigLoader:
return self.__config
# pylint: disable=invalid-name
def y(self, path: str, default=None, sep='.') -> Any:
def y(self, path: str, default=None, sep=".") -> Any:
"""Access attribute by using yaml path"""
# Walk sub_dicts before parsing path
root = self.raw
@ -138,7 +138,7 @@ class ConfigLoader:
def y_bool(self, path: str, default=False) -> bool:
"""Wrapper for y that converts value into boolean"""
return str(self.y(path, default)).lower() == 'true'
return str(self.y(path, default)).lower() == "true"
CONFIG = ConfigLoader()

View File

@ -7,8 +7,8 @@ from django.urls import reverse
from django.utils.functional import wraps
from django.utils.http import urlencode
RE_AUTH_KEY = getattr(settings, 'RE_AUTH_KEY', 'passbook_require_re_auth_done')
RE_AUTH_MARGAIN = getattr(settings, 'RE_AUTH_MARGAIN', 300)
RE_AUTH_KEY = getattr(settings, "RE_AUTH_KEY", "passbook_require_re_auth_done")
RE_AUTH_MARGAIN = getattr(settings, "RE_AUTH_MARGAIN", 300)
def reauth_required(view_function):
@ -21,25 +21,31 @@ def reauth_required(view_function):
request = args[0] if args else None
# Check if user is authenticated at all
if not request or not request.user or not request.user.is_authenticated:
return redirect(reverse('account-login'))
return redirect(reverse("account-login"))
now = timestamp()
if RE_AUTH_KEY in request.session and \
request.session[RE_AUTH_KEY] < (now - RE_AUTH_MARGAIN):
if RE_AUTH_KEY in request.session and request.session[RE_AUTH_KEY] < (
now - RE_AUTH_MARGAIN
):
# Timestamp in session but expired
del request.session[RE_AUTH_KEY]
if RE_AUTH_KEY not in request.session:
# Timestamp not in session, force user to reauth
return redirect(reverse('account-reauth') + '?' + urlencode({'next': request.path}))
return redirect(
reverse("account-reauth") + "?" + urlencode({"next": request.path})
)
if RE_AUTH_KEY in request.session and \
request.session[RE_AUTH_KEY] >= (now - RE_AUTH_MARGAIN) and \
request.session[RE_AUTH_KEY] <= now:
if (
RE_AUTH_KEY in request.session
and request.session[RE_AUTH_KEY] >= (now - RE_AUTH_MARGAIN)
and request.session[RE_AUTH_KEY] <= now
):
# Timestamp in session and valid
return view_function(*args, **kwargs)
# This should never be reached, just return False
return False # pragma: no cover
return wrap

View File

@ -10,7 +10,9 @@ from passbook.lib.widgets import DynamicArrayWidget
class DynamicArrayField(forms.Field):
"""Show array field as a dynamic amount of textboxes"""
default_error_messages = {"item_invalid": "Item %(nth)s in the array did not validate: "}
default_error_messages = {
"item_invalid": "Item %(nth)s in the array did not validate: "
}
def __init__(self, base_field, **kwargs):
self.base_field = base_field
@ -28,8 +30,10 @@ class DynamicArrayField(forms.Field):
except forms.ValidationError as error:
errors.append(
prefix_validation_error(
error, self.error_messages["item_invalid"],
code="item_invalid", params={"nth": index}
error,
self.error_messages["item_invalid"],
code="item_invalid",
params={"nth": index},
)
)
if errors:

View File

@ -6,6 +6,7 @@ from django.db import models
class CreatedUpdatedModel(models.Model):
"""Base Abstract Model to save created and update"""
created = models.DateTimeField(auto_now_add=True)
last_updated = models.DateTimeField(auto_now=True)

View File

@ -12,6 +12,7 @@ def before_send(event, hint):
from billiard.exceptions import WorkerLostError
from django.core.exceptions import DisallowedHost
from botocore.client import ClientError
ignored_classes = (
OperationalError,
ConnectionInterrupted,
@ -22,10 +23,10 @@ def before_send(event, hint):
DisallowedHost,
ConnectionResetError,
KeyboardInterrupt,
ClientError
ClientError,
)
if 'exc_info' in hint:
_exc_type, exc_value, _ = hint['exc_info']
if "exc_info" in hint:
_exc_type, exc_value, _ = hint["exc_info"]
if isinstance(exc_value, ignored_classes):
LOGGER.info("Supressing error %r", exc_value)
return None

View File

@ -6,8 +6,9 @@ from passbook.root.celery import CELERY_APP
LOGGER = get_logger()
@CELERY_APP.task()
def backup_database():
"""Backup database"""
management.call_command('dbbackup')
LOGGER.info('Successfully backed up database.')
management.call_command("dbbackup")
LOGGER.info("Successfully backed up database.")

View File

@ -10,11 +10,11 @@ register = template.Library()
@register.simple_tag()
def inline_static(path):
"""Inline static asset. If file is binary, return b64 representation"""
prefix = 'data:image/svg+xml;utf8,'
data = ''
full_path = settings.STATIC_ROOT + '/' + path
prefix = "data:image/svg+xml;utf8,"
data = ""
full_path = settings.STATIC_ROOT + "/" + path
if os.path.exists(full_path):
if full_path.endswith('.svg'):
if full_path.endswith(".svg"):
with open(full_path) as _file:
data = _file.read()
return prefix + data

View File

@ -10,22 +10,23 @@ LOGGER = get_logger()
@register.simple_tag(takes_context=True)
def is_active(context, *args, **kwargs):
"""Return whether a navbar link is active or not."""
request = context.get('request')
app_name = kwargs.get('app_name', None)
request = context.get("request")
app_name = kwargs.get("app_name", None)
if not request.resolver_match:
return ''
return ""
for url in args:
short_url = url.split(':')[1] if ':' in url else url
short_url = url.split(":")[1] if ":" in url else url
# Check if resolver_match matches
if request.resolver_match.url_name.startswith(url) or \
request.resolver_match.url_name.startswith(short_url):
if request.resolver_match.url_name.startswith(
url
) or request.resolver_match.url_name.startswith(short_url):
# Monkeypatch app_name: urls from core have app_name == ''
# since the root urlpatterns have no namespace
if app_name and request.resolver_match.app_name == app_name:
return 'active'
return "active"
if app_name is None:
return 'active'
return ''
return "active"
return ""
@register.simple_tag(takes_context=True)
@ -33,26 +34,28 @@ def is_active_url(context, view):
"""Return whether a navbar link is active or not."""
# matching_url = reverse(view, args=args, kwargs=kwargs)
request = context.get('request')
current_full_url = f"{request.resolver_match.app_name}:{request.resolver_match.url_name}"
request = context.get("request")
current_full_url = (
f"{request.resolver_match.app_name}:{request.resolver_match.url_name}"
)
if not request.resolver_match:
return ''
return ""
if current_full_url == view:
return 'active'
return "active"
# if matching_url == request.path:
# return 'active'
return ''
return ""
@register.simple_tag(takes_context=True)
def is_active_app(context, *args):
"""Return True if current link is from app"""
request = context.get('request')
request = context.get("request")
if not request.resolver_match:
return ''
return ""
for app_name in args:
if request.resolver_match.app_name == app_name:
return 'active'
return ''
return "active"
return ""

View File

@ -18,19 +18,19 @@ register = template.Library()
def back(context):
"""Return a link back (either from GET paramter or referer."""
request = context.get('request')
url = ''
if 'HTTP_REFERER' in request.META:
url = request.META.get('HTTP_REFERER')
if 'back' in request.GET:
url = request.GET.get('back')
request = context.get("request")
url = ""
if "HTTP_REFERER" in request.META:
url = request.META.get("HTTP_REFERER")
if "back" in request.GET:
url = request.GET.get("back")
if not is_url_absolute(url):
return url
return ''
return ""
@register.filter('fieldtype')
@register.filter("fieldtype")
def fieldtype(field):
"""Return classname"""
# if issubclass(field.__class__, CastableModel):
@ -43,34 +43,40 @@ def fieldtype(field):
@register.simple_tag(takes_context=True)
def title(context, *title):
"""Return either just branding or title - branding"""
branding = CONFIG.y('passbook.branding', 'passbook')
branding = CONFIG.y("passbook.branding", "passbook")
if not title:
return branding
# Include App Title in title
app = ''
if context.request.resolver_match and context.request.resolver_match.namespace != '':
app = ""
if (
context.request.resolver_match
and context.request.resolver_match.namespace != ""
):
dj_app = None
namespace = context.request.resolver_match.namespace.split(':')[0]
namespace = context.request.resolver_match.namespace.split(":")[0]
# New label (App URL Namespace == App Label)
dj_app = apps.get_app_config(namespace)
title_modifier = getattr(dj_app, 'title_modifier', None)
title_modifier = getattr(dj_app, "title_modifier", None)
if title_modifier:
app_title = dj_app.title_modifier(context.request)
app = app_title + ' -'
return _("%(title)s - %(app)s %(branding)s" % {
'title': ' - '.join([str(x) for x in title]),
'branding': branding,
'app': app,
})
app = app_title + " -"
return _(
"%(title)s - %(app)s %(branding)s"
% {
"title": " - ".join([str(x) for x in title]),
"branding": branding,
"app": app,
}
)
@register.simple_tag
def config(path, default=''):
def config(path, default=""):
"""Get a setting from the database. Returns default is setting doesn't exist."""
return CONFIG.y(path, default)
@register.filter(name='css_class')
@register.filter(name="css_class")
def css_class(field, css):
"""Add css class to form field"""
return field.as_widget(attrs={"class": css})
@ -90,16 +96,15 @@ def gravatar(email, size=None, rating=None):
{% gravatar someone@example.com 48 pg %}
"""
# gravatar uses md5 for their URLs, so md5 can't be avoided
gravatar_url = "%savatar/%s" % ('https://secure.gravatar.com/',
md5(email.encode('utf-8')).hexdigest()) # nosec
gravatar_url = "%savatar/%s" % (
"https://secure.gravatar.com/",
md5(email.encode("utf-8")).hexdigest(),
) # nosec
parameters = [p for p in (
('s', size or '158'),
('r', rating or 'g'),
) if p[1]]
parameters = [p for p in (("s", size or "158"), ("r", rating or "g"),) if p[1]]
if parameters:
gravatar_url += '?' + urlencode(parameters, doseq=True)
gravatar_url += "?" + urlencode(parameters, doseq=True)
return escape(gravatar_url)
@ -108,7 +113,7 @@ def gravatar(email, size=None, rating=None):
def verbose_name(obj):
"""Return Object's Verbose Name"""
if not obj:
return ''
return ""
return obj._meta.verbose_name
@ -116,5 +121,5 @@ def verbose_name(obj):
def form_verbose_name(obj):
"""Return ModelForm's Object's Verbose Name"""
if not obj:
return ''
return ""
return obj._meta.model._meta.verbose_name

View File

@ -8,9 +8,9 @@ def _get_client_ip_from_meta(meta: Dict[str, Any]) -> Optional[str]:
"""Attempt to get the client's IP by checking common HTTP Headers.
Returns none if no IP Could be found"""
headers = (
'HTTP_X_FORWARDED_FOR',
'HTTP_X_REAL_IP',
'REMOTE_ADDR',
"HTTP_X_FORWARDED_FOR",
"HTTP_X_REAL_IP",
"REMOTE_ADDR",
)
for _header in headers:
if _header in meta:

View File

@ -4,15 +4,15 @@ from importlib import import_module
def class_to_path(cls):
"""Turn Class (Class or instance) into module path"""
return '%s.%s' % (cls.__module__, cls.__name__)
return "%s.%s" % (cls.__module__, cls.__name__)
def path_to_class(path):
"""Import module and return class"""
if not path:
return None
parts = path.split('.')
package = '.'.join(parts[:-1])
parts = path.split(".")
package = ".".join(parts[:-1])
_class = getattr(import_module(package), parts[-1])
return _class
@ -20,11 +20,14 @@ def path_to_class(path):
def get_apps():
"""Get list of all passbook apps"""
from django.apps.registry import apps
for _app in apps.get_app_configs():
if _app.name.startswith('passbook'):
if _app.name.startswith("passbook"):
yield _app
def app(name):
"""Return true if app with `name` is enabled"""
from django.conf import settings
return name in settings.INSTALLED_APPS

View File

@ -1,7 +1,8 @@
"""passbook UI utils"""
def human_list(_list) -> str:
"""Convert a list of items into 'a, b or c'"""
last_item = _list.pop()
result = ', '.join(_list)
return '%s or %s' % (result, last_item)
result = ", ".join(_list)
return "%s or %s" % (result, last_item)

View File

@ -8,16 +8,18 @@ class CreateAssignPermView(CreateView):
"""Assign permissions to object after creation"""
permissions = [
'%s.view_%s',
'%s.change_%s',
'%s.delete_%s',
"%s.view_%s",
"%s.change_%s",
"%s.delete_%s",
]
def form_valid(self, form):
response = super().form_valid(form)
for permission in self.permissions:
full_permission = permission % (
self.object._meta.app_label, self.object._meta.model_name)
self.object._meta.app_label,
self.object._meta.model_name,
)
print(full_permission)
assign_perm(full_permission, self.request.user, self.object)
return response