From dc67ea317b5f7194285cc1a31d3a9ee953c8021b Mon Sep 17 00:00:00 2001 From: Alexandre Iooss Date: Mon, 8 Jul 2019 12:55:48 +0200 Subject: [PATCH] Regroup everything here --- .coveragerc | 10 + .gitlab-ci.yml | 21 + .pylintrc | 379 ++++++++++++++++++ note_adherents/__init__.py | 0 note_adherents/models.py | 75 ++++ note_adherents/tests/__init__.py | 0 note_theme/__init__.py | 0 note_theme/locale/fr/LC_MESSAGES/django.po | 104 +++++ note_theme/static/css/admin.css | 141 +++++++ .../static/favicon/android-chrome-192x192.png | Bin 0 -> 9915 bytes .../static/favicon/android-chrome-512x512.png | Bin 0 -> 27174 bytes .../static/favicon/apple-touch-icon.png | Bin 0 -> 6523 bytes note_theme/static/favicon/browserconfig.xml | 9 + note_theme/static/favicon/favicon-16x16.png | Bin 0 -> 690 bytes note_theme/static/favicon/favicon-32x32.png | Bin 0 -> 1482 bytes note_theme/static/favicon/favicon.ico | Bin 0 -> 15086 bytes note_theme/static/favicon/mstile-150x150.png | Bin 0 -> 5671 bytes .../static/favicon/safari-pinned-tab.svg | 1 + note_theme/static/favicon/site.webmanifest | 19 + note_theme/templates/admin/base_site.html | 96 +++++ .../templates/registration/logged_out.html | 11 + .../registration/password_change_done.html | 11 + .../registration/password_change_form.html | 11 + .../registration/password_reset_complete.html | 11 + .../registration/password_reset_confirm.html | 11 + .../registration/password_reset_done.html | 11 + .../registration/password_reset_email.html | 13 + .../registration/password_reset_form.html | 11 + note_theme/tests/__init__.py | 0 note_theme/tests/test_templates.py | 44 ++ tox.ini | 49 +++ 31 files changed, 1038 insertions(+) create mode 100644 .coveragerc create mode 100644 .gitlab-ci.yml create mode 100644 .pylintrc create mode 100644 note_adherents/__init__.py create mode 100644 note_adherents/models.py create mode 100644 note_adherents/tests/__init__.py create mode 100644 note_theme/__init__.py create mode 100644 note_theme/locale/fr/LC_MESSAGES/django.po create mode 100644 note_theme/static/css/admin.css create mode 100644 note_theme/static/favicon/android-chrome-192x192.png create mode 100644 note_theme/static/favicon/android-chrome-512x512.png create mode 100644 note_theme/static/favicon/apple-touch-icon.png create mode 100644 note_theme/static/favicon/browserconfig.xml create mode 100644 note_theme/static/favicon/favicon-16x16.png create mode 100644 note_theme/static/favicon/favicon-32x32.png create mode 100644 note_theme/static/favicon/favicon.ico create mode 100644 note_theme/static/favicon/mstile-150x150.png create mode 100644 note_theme/static/favicon/safari-pinned-tab.svg create mode 100644 note_theme/static/favicon/site.webmanifest create mode 100644 note_theme/templates/admin/base_site.html create mode 100644 note_theme/templates/registration/logged_out.html create mode 100644 note_theme/templates/registration/password_change_done.html create mode 100644 note_theme/templates/registration/password_change_form.html create mode 100644 note_theme/templates/registration/password_reset_complete.html create mode 100644 note_theme/templates/registration/password_reset_confirm.html create mode 100644 note_theme/templates/registration/password_reset_done.html create mode 100644 note_theme/templates/registration/password_reset_email.html create mode 100644 note_theme/templates/registration/password_reset_form.html create mode 100644 note_theme/tests/__init__.py create mode 100644 note_theme/tests/test_templates.py create mode 100644 tox.ini diff --git a/.coveragerc b/.coveragerc new file mode 100644 index 00000000..f21739a5 --- /dev/null +++ b/.coveragerc @@ -0,0 +1,10 @@ +[run] +source = + note_kfet + note_theme + note_adherents +omit = + note_theme/tests/*.py + note_theme/migrations/*.py + note_adherents/tests/*.py + note_adherents/migrations/*.py diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml new file mode 100644 index 00000000..bceb5f51 --- /dev/null +++ b/.gitlab-ci.yml @@ -0,0 +1,21 @@ +image: python:3.6 + +stages: + - test + +before_script: + - pip install tox + +python36: + image: python:3.6 + stage: test + script: tox -e py36 + +python37: + image: python:3.7 + stage: test + script: tox -e py37 + +linters: + stage: test + script: tox -e linters diff --git a/.pylintrc b/.pylintrc new file mode 100644 index 00000000..6ddf1f3c --- /dev/null +++ b/.pylintrc @@ -0,0 +1,379 @@ +[MASTER] + +# Specify a configuration file. +#rcfile= + +# Python code to execute, usually for sys.path manipulation such as +# pygtk.require(). +#init-hook= + +# Add files or directories to the blacklist. They should be base names, not +# paths. +ignore=CVS,.git + +# Pickle collected data for later comparisons. +persistent=yes + +# List of plugins (as comma separated values of python modules names) to load, +# usually to register additional checkers. +load-plugins= + +# Use multiple processes to speed up Pylint. +jobs=4 + +# Allow loading of arbitrary C extensions. Extensions are imported into the +# active Python interpreter and may run arbitrary code. +unsafe-load-any-extension=no + +# A comma-separated list of package or module names from where C extensions may +# be loaded. Extensions are loading into the active Python interpreter and may +# run arbitrary code +extension-pkg-whitelist= + +# Allow optimization of some AST trees. This will activate a peephole AST +# optimizer, which will apply various small optimizations. For instance, it can +# be used to obtain the result of joining multiple strings with the addition +# operator. Joining a lot of strings can lead to a maximum recursion error in +# Pylint and this flag can prevent that. It has one side effect, the resulting +# AST will be different than the one from reality. +optimize-ast=no + + +[MESSAGES CONTROL] + +# Only show warnings with the listed confidence levels. Leave empty to show +# all. Valid levels: HIGH, INFERENCE, INFERENCE_FAILURE, UNDEFINED +confidence=INFERENCE_FAILURE + +# Enable the message, report, category or checker with the given id(s). You can +# either give multiple identifier separated by comma (,) or put this option +# multiple time. See also the "--disable" option for examples. +#enable= + +# Disable the message, report, category or checker with the given id(s). You +# can either give multiple identifiers separated by comma (,) or put this +# option multiple times (only on the command line, not in the configuration +# file where it should appear only once).You can also use "--disable=all" to +# disable everything first and then reenable specific checks. For example, if +# you want to run only the similarities checker, you can use "--disable=all +# --enable=similarities". If you want to run only the classes checker, but have +# no Warning level messages displayed, use"--disable=all --enable=classes +# --disable=W" +disable=intern-builtin,nonzero-method,parameter-unpacking,backtick,raw_input-builtin,dict-view-method,filter-builtin-not-iterating,long-builtin,unichr-builtin,input-builtin,unicode-builtin,file-builtin,map-builtin-not-iterating,delslice-method,apply-builtin,cmp-method,setslice-method,coerce-method,long-suffix,raising-string,import-star-module-level,buffer-builtin,reload-builtin,unpacking-in-except,print-statement,hex-method,old-octal-literal,metaclass-assignment,dict-iter-method,range-builtin-not-iterating,using-cmp-argument,indexing-exception,no-absolute-import,coerce-builtin,getslice-method,suppressed-message,execfile-builtin,round-builtin,useless-suppression,reduce-builtin,old-raise-syntax,zip-builtin-not-iterating,cmp-builtin,xrange-builtin,standarderror-builtin,old-division,oct-method,next-method-called,old-ne-operator,basestring-builtin + + +[REPORTS] + +# Set the output format. Available formats are text, parseable, colorized, msvs +# (visual studio) and html. You can also give a reporter class, eg +# mypackage.mymodule.MyReporterClass. +output-format=text + +# Put messages in a separate file for each module / package specified on the +# command line instead of printing them on stdout. Reports (if any) will be +# written in a file name "pylint_global.[txt|html]". +files-output=no + +# Tells whether to display a full report or only the messages +reports=no + +# Python expression which should return a note less than 10 (10 is the highest +# note). You have access to the variables errors warning, statement which +# respectively contain the number of errors / warnings messages and the total +# number of statements analyzed. This is used by the global evaluation report +# (RP0004). +evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10) + +# Template used to display messages. This is a python new-style format string +# used to format the message information. See doc for all details +#msg-template= + + +[BASIC] + +# List of builtins function names that should not be used, separated by a comma +bad-functions=map,filter + +# Good variable names which should always be accepted, separated by a comma +good-names=i,j,k,ex,Run,_ + +# Bad variable names which should always be refused, separated by a comma +bad-names=foo,bar,baz,toto,tutu,tata + +# Colon-delimited sets of names that determine each other's naming style when +# the name regexes allow several styles. +name-group= + +# Include a hint for the correct naming format with invalid-name +include-naming-hint=yes + +# Regular expression matching correct argument names +argument-rgx=[a-z_][a-z0-9_]{2,30}$ + +# Naming hint for argument names +argument-name-hint=[a-z_][a-z0-9_]{2,30}$ + +# Regular expression matching correct attribute names +attr-rgx=[a-z_][a-z0-9_]{2,30}$ + +# Naming hint for attribute names +attr-name-hint=[a-z_][a-z0-9_]{2,30}$ + +# Regular expression matching correct constant names +const-rgx=(([A-Z_][A-Z0-9_]*)|(__.*__))$ + +# Naming hint for constant names +const-name-hint=(([A-Z_][A-Z0-9_]*)|(__.*__))$ + +# Regular expression matching correct class names +class-rgx=[A-Z_][a-zA-Z0-9]+$ + +# Naming hint for class names +class-name-hint=[A-Z_][a-zA-Z0-9]+$ + +# Regular expression matching correct inline iteration names +inlinevar-rgx=[A-Za-z_][A-Za-z0-9_]*$ + +# Naming hint for inline iteration names +inlinevar-name-hint=[A-Za-z_][A-Za-z0-9_]*$ + +# Regular expression matching correct class attribute names +class-attribute-rgx=([A-Za-z_][A-Za-z0-9_]{2,30}|(__.*__))$ + +# Naming hint for class attribute names +class-attribute-name-hint=([A-Za-z_][A-Za-z0-9_]{2,30}|(__.*__))$ + +# Regular expression matching correct function names +function-rgx=[a-z_][a-z0-9_]{2,30}$ + +# Naming hint for function names +function-name-hint=[a-z_][a-z0-9_]{2,30}$ + +# Regular expression matching correct module names +module-rgx=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$ + +# Naming hint for module names +module-name-hint=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$ + +# Regular expression matching correct method names +method-rgx=[a-z_][a-z0-9_]{2,30}$ + +# Naming hint for method names +method-name-hint=[a-z_][a-z0-9_]{2,30}$ + +# Regular expression matching correct variable names +variable-rgx=[a-z_][a-z0-9_]{2,30}$ + +# Naming hint for variable names +variable-name-hint=[a-z_][a-z0-9_]{2,30}$ + +# Regular expression which should only match function or class names that do +# not require a docstring. +no-docstring-rgx=^_ + +# Minimum line length for functions/classes that require docstrings, shorter +# ones are exempt. +docstring-min-length=-1 + + +[ELIF] + +# Maximum number of nested blocks for function / method body +max-nested-blocks=5 + + +[FORMAT] + +# Maximum number of characters on a single line. +max-line-length=100 + +# Regexp for a line that is allowed to be longer than the limit. +ignore-long-lines=^\s*(# )??$ + +# Allow the body of an if to be on the same line as the test if there is no +# else. +single-line-if-stmt=no + +# List of optional constructs for which whitespace checking is disabled. `dict- +# separator` is used to allow tabulation in dicts, etc.: {1 : 1,\n222: 2}. +# `trailing-comma` allows a space between comma and closing bracket: (a, ). +# `empty-line` allows space-only lines. +no-space-check=trailing-comma,dict-separator + +# Maximum number of lines in a module +max-module-lines=1000 + +# String used as indentation unit. This is usually " " (4 spaces) or "\t" (1 +# tab). +indent-string=' ' + +# Number of spaces of indent required inside a hanging or continued line. +indent-after-paren=4 + +# Expected format of line ending, e.g. empty (any line ending), LF or CRLF. +expected-line-ending-format= + + +[LOGGING] + +# Logging modules to check that the string format arguments are in logging +# function parameter format +logging-modules=logging + + +[MISCELLANEOUS] + +# List of note tags to take in consideration, separated by a comma. +notes=FIXME,XXX,TODO + + +[SIMILARITIES] + +# Minimum lines number of a similarity. +min-similarity-lines=4 + +# Ignore comments when computing similarities. +ignore-comments=yes + +# Ignore docstrings when computing similarities. +ignore-docstrings=yes + +# Ignore imports when computing similarities. +ignore-imports=no + + +[SPELLING] + +# Spelling dictionary name. Available dictionaries: none. To make it working +# install python-enchant package. +spelling-dict= + +# List of comma separated words that should not be checked. +spelling-ignore-words= + +# A path to a file that contains private dictionary; one word per line. +spelling-private-dict-file= + +# Tells whether to store unknown words to indicated private dictionary in +# --spelling-private-dict-file option instead of raising a message. +spelling-store-unknown-words=no + + +[TYPECHECK] + +# Tells whether missing members accessed in mixin class should be ignored. A +# mixin class is detected if its name ends with "mixin" (case insensitive). +ignore-mixin-members=yes + +# List of module names for which member attributes should not be checked +# (useful for modules/projects where namespaces are manipulated during runtime +# and thus existing member attributes cannot be deduced by static analysis. It +# supports qualified module names, as well as Unix pattern matching. +ignored-modules= + +# List of classes names for which member attributes should not be checked +# (useful for classes with attributes dynamically set). This supports can work +# with qualified names. +ignored-classes= + +# List of members which are set dynamically and missed by pylint inference +# system, and so shouldn't trigger E1101 when accessed. Python regular +# expressions are accepted. +generated-members= + + +[VARIABLES] + +# Tells whether we should check for unused import in __init__ files. +init-import=no + +# A regular expression matching the name of dummy variables (i.e. expectedly +# not used). +dummy-variables-rgx=_$|dummy + +# List of additional names supposed to be defined in builtins. Remember that +# you should avoid to define new builtins when possible. +additional-builtins= + +# List of strings which can identify a callback function by name. A callback +# name must start or end with one of those strings. +callbacks=cb_,_cb + + +[CLASSES] + +# List of method names used to declare (i.e. assign) instance attributes. +defining-attr-methods=__init__,__new__,setUp + +# List of valid names for the first argument in a class method. +valid-classmethod-first-arg=cls + +# List of valid names for the first argument in a metaclass class method. +valid-metaclass-classmethod-first-arg=mcs + +# List of member names, which should be excluded from the protected access +# warning. +exclude-protected=_asdict,_fields,_replace,_source,_make + + +[DESIGN] + +# Maximum number of arguments for function / method +max-args=20 + +# Argument names that match this expression will be ignored. Default to name +# with leading underscore +ignored-argument-names=_.* + +# Maximum number of locals for function / method body +max-locals=20 + +# Maximum number of return / yield for function / method body +max-returns=6 + +# Maximum number of branch for function / method body +max-branches=12 + +# Maximum number of statements in function / method body +max-statements=50 + +# Maximum number of parents for a class (see R0901). +max-parents=7 + +# Maximum number of attributes for a class (see R0902). +max-attributes=10 + +# Minimum number of public methods for a class (see R0903). +min-public-methods=2 + +# Maximum number of public methods for a class (see R0904). +max-public-methods=20 + +# Maximum number of boolean expressions in an if statement +max-bool-expr=5 + + +[IMPORTS] + +# Deprecated modules which should not be used, separated by a comma +deprecated-modules=optparse + +# Create a graph of every (i.e. internal and external) dependencies in the +# given file (report RP0402 must not be disabled) +import-graph= + +# Create a graph of external dependencies in the given file (report RP0402 must +# not be disabled) +ext-import-graph= + +# Create a graph of internal dependencies in the given file (report RP0402 must +# not be disabled) +int-import-graph= + + +[EXCEPTIONS] + +# Exceptions that will emit a warning when being caught. Defaults to +# "Exception" +overgeneral-exceptions=Exception + diff --git a/note_adherents/__init__.py b/note_adherents/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/note_adherents/models.py b/note_adherents/models.py new file mode 100644 index 00000000..b3034ed4 --- /dev/null +++ b/note_adherents/models.py @@ -0,0 +1,75 @@ +# -*- mode: python; coding: utf-8 -*- +# Copyright (C) 2016-2019 by BDE +# SPDX-License-Identifier: GPL-3.0-or-later + +from django.conf import settings +from django.contrib.auth.models import User +from django.db import models +from django.db.models.signals import post_save +from django.dispatch import receiver +from django.utils.translation import gettext_lazy as _ + + +class Profile(models.Model): + """ + An user profile + + We do not want to patch the Django Contrib Auth User class + so this model add an user profile with additional information. + """ + user = models.OneToOneField( + settings.AUTH_USER_MODEL, + on_delete=models.CASCADE, + ) + phone_number = models.CharField( + max_length=255, + verbose_name=_('phone number'), + ) + section = models.CharField( + max_length=255, + verbose_name=_('section'), + help_text=_('e.g. "1A0", "9A♥", "SAPHIRE"'), + ) + + class Meta: + verbose_name = _('user profile') + verbose_name_plural = _('user profile') + + def __str__(self): + return self.user.get_username() + + +class MembershipFee(models.Model): + """ + TODO + """ + user = models.ForeignKey( + settings.AUTH_USER_MODEL, + on_delete=models.PROTECT, + ) + date = models.CharField( + max_length=255, + verbose_name=_('phone number'), + ) + amount = models.CharField( + max_length=255, + verbose_name=_('section'), + help_text=_('e.g. "1A0", "9A♥", "SAPHIRE"'), + ) + + class Meta: + verbose_name = _('user profile') + verbose_name_plural = _('user profile') + + def __str__(self): + return self.user.get_username() + + +@receiver(post_save, sender=User) +def save_user_profile(sender, instance, created, **_kwargs): + """ + Hook to save an user profile when an user is updated + """ + if created: + Profile.objects.create(user=instance) + instance.profile.save() diff --git a/note_adherents/tests/__init__.py b/note_adherents/tests/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/note_theme/__init__.py b/note_theme/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/note_theme/locale/fr/LC_MESSAGES/django.po b/note_theme/locale/fr/LC_MESSAGES/django.po new file mode 100644 index 00000000..0a74fa30 --- /dev/null +++ b/note_theme/locale/fr/LC_MESSAGES/django.po @@ -0,0 +1,104 @@ +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2019-06-30 16:26+0200\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n > 1);\n" + +#: templates/admin/base_site.html:22 templates/base.html:48 +msgid "Welcome," +msgstr "" + +#: templates/admin/base_site.html:27 +msgid "View site" +msgstr "Retour au site" + +#: templates/admin/base_site.html:32 templates/admin/base_site.html:51 +#: templates/base.html:52 +msgid "View admin" +msgstr "Administration" + +#: templates/admin/base_site.html:44 +msgid "Documentation" +msgstr "" + +#: templates/admin/base_site.html:53 templates/base.html:56 +msgid "Log out" +msgstr "" + +#: templates/base.html:62 templates/registration/login.html:9 +#: templates/registration/login.html:56 +msgid "Log in" +msgstr "" + +#: templates/registration/logged_out.html:9 +#: templates/registration/password_change_done.html:9 +#: templates/registration/password_change_form.html:9 +#: templates/registration/password_reset_complete.html:9 +#: templates/registration/password_reset_confirm.html:9 +#: templates/registration/password_reset_done.html:9 +#: templates/registration/password_reset_form.html:9 +msgid "Home" +msgstr "" + +#: templates/registration/login.html:14 +msgid "Please correct the error below." +msgstr "" + +#: templates/registration/login.html:15 +msgid "Please correct the errors below." +msgstr "" + +#: templates/registration/login.html:31 +#, python-format +msgid "" +"You are authenticated as %(username)s, but are not authorized to access this " +"page. Would you like to login to a different account?" +msgstr "" + +#: templates/registration/login.html:52 +msgid "Forgotten your password?" +msgstr "Mot de passe oublié ?" + +#: templates/registration/password_change_done.html:9 +#: templates/registration/password_change_form.html:9 +msgid "Password change" +msgstr "" + +#: templates/registration/password_reset_complete.html:9 +#: templates/registration/password_reset_done.html:9 +#: templates/registration/password_reset_form.html:9 +msgid "Password reset" +msgstr "" + +#: templates/registration/password_reset_confirm.html:9 +msgid "Password reset confirmation" +msgstr "" + +#: templates/registration/password_reset_email.html:2 +#, python-format +msgid "" +"You're receiving this email because you requested a password reset for your " +"user account at %(site_name)s." +msgstr "" + +#: templates/registration/password_reset_email.html:4 +msgid "Please go to the following page and choose a new password:" +msgstr "" + +#: templates/registration/password_reset_email.html:9 +msgid "Thanks for using our site!" +msgstr "" + +#: templates/registration/password_reset_email.html:11 +#, python-format +msgid "The %(site_name)s team" +msgstr "" diff --git a/note_theme/static/css/admin.css b/note_theme/static/css/admin.css new file mode 100644 index 00000000..59b09f36 --- /dev/null +++ b/note_theme/static/css/admin.css @@ -0,0 +1,141 @@ +/* + * SPDX-License-Identifier: GPL-3.0-or-later + * + * Copyright © 2019 Alexandre Iooss + * + * This is the custom style for Django Contrib Admin + */ + +/* Colors */ +#header { + background-color: #151515; + border-bottom: solid 5px #d80029; + padding: 10px 40px; +} + +.module h2, .module caption, .inline-group h2 { + background: #e6e0d8; + color: #222; +} + +a.section:link, a.section:visited { + color: #222; +} + +#user-tools a { + border-bottom: none; + font-weight: bold; +} + +div.breadcrumbs { + background: #3c3c3c; +} + +.button, input[type=submit], input[type=button], .submit-row input, a.button { + background: #d8a456; +} + +.button:active, input[type=submit]:active, input[type=button]:active, .button:focus, input[type=submit]:focus, +input[type=button]:focus, .button:hover, input[type=submit]:hover, input[type=button]:hover { + background: #b98d4a; +} + +.button.default, input[type=submit].default, .submit-row input.default { + background: #b98d4a; +} + +.button.default:active, input[type=submit].default:active, .button.default:focus, input[type=submit].default:focus, +.button.default:hover, input[type=submit].default:hover { + background: #a7752b; +} + +/* User tools top menu */ +#user-tools .dropdown:hover > a, #user-tools .dropdown:focus > a { + color: #79aec8; +} + +#user-tools .dropdown { + position: relative; /* needed to position the dropdown content */ + display: inline-block; +} + +#user-tools .dropdown-content { + display: block; + position: absolute; + background-color: #444444; + min-width: 180px; + box-shadow: 0 8px 16px 0 rgba(0, 0, 0, 0.2); + z-index: 2000; + text-align: left; + + /* Hide menu by making it transparent */ + transition: opacity 100ms, visibility 100ms; + opacity: 0; + visibility: hidden; +} + +#user-tools .dropdown-content a { + color: #fff; + padding: 7px 8px; + text-decoration: none; + display: block; + line-height: 16px; +} + +#user-tools .dropdown-content a:hover { + background-color: #636363; +} + +#user-tools .dropdown:hover .dropdown-content { + opacity: 1; + visibility: visible; +} + +/* Fix navigation hidden */ +#header { + overflow: visible; +} + +.login #header { + overflow: hidden; +} + +/* Footer */ +#footer { + padding: 20px 40px; + color: #999; +} + +.login #footer { + padding: 10px; + font-size: 10pt; +} + +#footer a { + color: #777; +} + +#footer select { + height: 24px; + padding: 0; +} + +/* Pull footer to bottom */ +#content { + min-height: calc(100vh - 190px); +} + +.login #content { + min-height: 0; +} + +/* Recenter login button */ +.login .submit-row { + padding: 1em 0 0 0 !important; + text-align: center !important; +} + +/* Dashboard should take all page */ +.dashboard #content { + width: auto; +} diff --git a/note_theme/static/favicon/android-chrome-192x192.png b/note_theme/static/favicon/android-chrome-192x192.png new file mode 100644 index 0000000000000000000000000000000000000000..5b31f298276637f9997dccc8dad10be846c5d136 GIT binary patch literal 9915 zcma)iRZtvE)Ah28EN+Wya3?sy-QC^Y7k76EZo%E10Kqjt(BSStf(3W^pZEH|`KGGp z^i1{Kba&01nmREmO46uEgh&7Y0995-LhV27|DS>3i6aZ*SM1D1e z`)>{7rY0>0sGlbO3jhG4RTMNN6>OpC$Y3})I5Z?M94ss>2o?bj4g~to0fB%(R3yaz zHdC>2qOq_$J3Ga(QP2<(aFCJe>S~jc5=%>p+%YjTGtZ-~p7&J6g zXh?_#`ntge2rLx1Uu_YJeGrmKAtb0^Y;;s%VL?qaStG**EiP<*aZFk{k}}-Z4kn9N}^gm>``&NxX&0BuH6Ym?tME7L+I>>99Kx5^F1qN(la4C#)?7#tJqO9|jUL1{e<+&W;YH zvZ8!Y4A&4Hb0!zIlo#u7BWzzH93CDdC@|nRHW39n{8bz5e`(pQfc+(bR~-buTnziC z4pv@XHp>m1&y6)Bg@4`xYw!sbWAwL@^bk9zx=O4chIlrlbx~ zXOJeqg~|{r^Gl`)*U) z0022aRzg(6du>5)(|+%faH(2z9riRr<|=I=(Uqa~X99>~F#5I_?=4tu{9-FjC6!kj zft^#7hV-7r(?)Ee6BG+W8y$<_1v!-#Z8G^Q`BD8wy|$Wjkn1?X_81mup!3q*_ux}- zM;TQtti8Jjj!+Fao z_*IyIaZHXfabdUJ_tZypUM~0y1e!<`EtexgIP}BAnWIArcwceZ-DSvBaLj& z3THBRL1UvZ;C%UyU$c=dOaR8Bk&dUov;BFHstM!Xa^TKf;Ll=1*AGD)2ZejU+EOx+ z3zpS6E8|u}BbiLFv*q8?RbEZg^kl(c3=Bj`)e73%Vk+|`NAdAH>^jAdaki*s%`B6o z(Ehi8blR-A=f|lCyrzmW1L3?C!&Q-S=#>l{ke&_V3iGP=c_{Ne5Hjz_L*V1hMsa%M zK+H3Lbsa-E(cO(O_6hvc@ab$jksbb& zN)E%Loj8+gef7D2#6!2Kb=Mw-B4YmGHC@b_Bn&$m?keRW{2)w}ZMUYR{d0t!IW0!m zFMUPP-(Z~m6z5wmm{Pb&-2X2PFZ8V5sAT<;RVOU(%{+1R{YWHdG6<%igG|fv77+BL zVLw+l?GAr??fBQ9ToMEMZU*k=$@@@_6b9A%w1q~uph-wpBjimTauP5(0{uSQp$F7e zUD67n10HBERauT#`Ax#lS4VzJ78tj5r&7b>x$MYGV(E8yf#+a32(-)DG2W)=BQ3R< z{;e&cEQyQyK#~|vZW?2iexda_vRPQ)65{*_06i5=sr2 z7&?kSqCFEtk>mY}UL%hpH5?cxHWC@QB3?vZ?59i?V8Vne?yY*FBGeJ|$nxG=30V^% zHk`zCJ2LewikBr$RIOQ7o zvHlQ1H|xY^L_`hI8d6K?6pQ%!uUe<)@9m=AbV|qG%;`dT3-T!@4UMxXbk#-WBTB|p( z|CvTxc6s>rd$8Ef;bA*5+(0UDqz&aK-Aa1ctba_%HIIJ&zKqKR-wn$5?k~OI2q9?> z0p$RXU(1PZI4u2KN%V1-di_w(!?A+`WSKU4IPL=G)-hPP_4)=<($MHQ#bB8v~k51-J>LBM}asc>b z%F*r$(_>VLm6>P;yhg7YSyWyg0Ge=DH;yoo(KWss(vJ{r>~Jg;$AmkMbyO)`T{MqK z#)dfKB5=ZUiOGRje80UG(#IOW5G$Q&Pd;qrEAM}xc!F6K=~Rjzyjc!FKR%BwjCBIWepodn zc9Zt;#sv>ZEaDJnzq(Nt5Qt5MD!Q{yWw^ zOBE+@0s*OMJ<0O&*cCn~3NBI>T$PpdML3b#DGRbrCOq`-!Ef2{^AQ^i6Njbk9GG*n z(ld9INZu;lN(UNZ(Y$=o+6AE^TiFHNR+tq6)_suPLxfkSH)8hs^x$N_gQnMc>>sZ7|Z+ ztmn`}J#^L`B1{h_O*Gc&bH6FkKB+WoiBdjlkZ~V@c?pYZyL?-JFll-CxRt-Wwa}@7cZ6kH{%VFFOQGwNRrf}~Q{>^{+ zVq$IGUgrp_G$HPXrgy7VqiOuC$SAU@=2M9VVq0%emaaD-u=i%aIt?Yfe4rwgHZQu# z+o$Xa;s4iZf+e=Rv`rf7b{(_y5%gyYzGum1_Air^Ba3^POL5R$fBLbOZW*iTKV2Q5 z%ItHXpH?5ieNNl6Ux=S`Wg8nx8A0l0(>MtSk_tS&ByS;Hd=IRYR>G4){ZokF;mJ)*2SkKhCG0tHWvr@52iIC^PR(M!k3T#eBvaK5Pz+uWVn{cPPkU3rO78VWzAAmIj_zgwyf3IV0dYt?g_>< zmrLVw{ck&Jm4P#yxz$_g_4x{A8kQAgyA`skzMF~Tj?3rwt*)RSQeE1bcKXU(BIvQ9 z<(`=`J0{Juc2(E1_%eZiJIqrL@goAj0rinUcfBdV^vt2C=K|HBVFWRfcI~;=N5t_L zA_dieeZHj*PVV#xdi0y^rcK)!!F|2Y7ky6XYSl7=Y zg>V>DfEWg0uP5;$AUdBxTO@~hpNEGOAyMSR_l)*+ttwOIx1_+@DK0aXbqCa%_w3p? zvEHp}UAzFtp~RLYX>?^J+DY5Gff>~Nom6Y3+Le+LrZ`RrOs z6I#y^i{E?~Q)AkrF})}&4IV)ZTr*Mu`WZ#>J-49}R~eG>nfzX=o~vf1k`{l0C(A?@ zj+pD^y^JP5u3>VnU+YoU-Qb|hFuMoQv(O=-J<_YmSpJq(N|K4(mm%QWaR=qPUEb!D z%?dywh=Qt}{~^{1wbp5NnJJc4m5zxjq}Ep>T3TIC03dL=+U4`GRgWo3vR1vu3q^?g zTAldM^r2sQnu6P zro+N!r&AD7l(}~A7lZupCW012}r%X*H zh`l4y7XjhmCn_}@E_Q#|$Jx4|Fko_^hfvi z2nt3hbb=_0ctC!>g=M%_L)>RLon{YJq&CYoj|>%&avkEa zl;u%?g2Q+!cl^qa_Q7mp(+o|)n0&MsI=%}q^QVQyl)A7Z;Lj+c*Wc4p@FbG@>_hjXOlKubPB9`^ z(0ed!WpAl{5+3dh!-N9@nnuRY{eo7SF^dr4K|kWLnPSwOh%>*SnPZ5S6AQ3O6M##@ zb1sNyF!N^wf->BKC)kh?{9TOtCqLdEz~dE(E~}?P$LZ$$bnCc z+2_bm#ZfAd52{C!ZbnImk5iIqSIQ)B-i0ppCDY5sIo_Kp*msTN?tvGcu7CnYK$miw zo@3;E@npH4ju2w#slJKhd3X0%k}R=0WqY8Q8!B%Z%oYfF}VKmWp*0 zZTfvoY%B^>w;n=$1iR@{Fen(3;bqwD*V*X2|xWxePV`zg0mV0Ygyj94YJ)(KVjkz zW;k%t46a#*e!Wbf6Ynyk(l4iUua2~^cqE&4j9mxp(Kvjluvjcmw0$HQ_>MA&JJFVVt{tZ{kbop^gEA=6@YPAUW(G6%y z5!=Gb8ZQOT*8JVbozIq7O9I@w0{Ch!~8&+ z%%)lt#u&3nqLy60ORg+dOWowB5ftj$VUOp$W{i^E|N$fK$^=pTH6w3WD2k`ocYPWI|i|RHPSA4qNdW= zA zhs(+bLsb^ZHL`2�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 z004NL + + + + + #da532c + + + diff --git a/note_theme/static/favicon/favicon-16x16.png b/note_theme/static/favicon/favicon-16x16.png new file mode 100644 index 0000000000000000000000000000000000000000..5db7ed945375943b1950cd0878c568b7f8d60d09 GIT binary patch literal 690 zcmV;j0!{siP)Px#^H5AwMNDaNs}2~aF%q3e3u7@KX9^HtBMog{YmYt+ zpr4w)R1U(z!rI!}u_+bb-`}sVu2n`uva+#hCl8;XpL1C>f+Huu&(G4*)7{?Q*4WpQ zfO&EZ5>g-yY9|i2E)=0T7fc)ryu7=1LNHPw4ZB(mrKO~`Cl!ZnVa&|T%uf;4*44qZ zio#71#zzvfcL$P?bbL)c@$vD{(bAwp3&FdmxNbPf$;rMxInl_*wt!~X*x09xbh$Yb zy*&}ku3e-=MyN0+rj3rP9wCBHO@~1~elZrLI~T->OS&Z=r&vCDOFXKVevo-yxm*p% zIuy5W3w>Qg`b5u*0000*bW%=J02gXf8VUFVVIt~tv-$c65;6TiC@&Eu(wT85YP@*a zy3O8D)MZi4@y%GGto^J+d7FdCKg3f*+xzjL)$#H1^?}ZY#a?_@vH$=8sYygZR2b7$ z&eaaWPz(m(`I!sz;qLCP6P)*d8V1WDqZdv8FHKqmi3-(`|El0&14$BQvK0cFp~NrQl{?oXl3!UbSV*Fx}MX#l?2>|3*WAPjMaD}O}d#f81!o}7VI%QF#hntnK{ zTtiW%5Ex#ZFw5PzE5j3tZH_j+-vqxW48(ceu2nhqc#le43PcPr&pT)1P)xXPnv4OF zqo`Cgz5&f756;e|MB)Gd09SfcSaechcOY6Cgx@G{a;ABePT>%h=S&#LUDT#0SfONT5nC Y0O}VJbn-$ql>h($07*qoM6N<$f>Qq`ZvX%Q literal 0 HcmV?d00001 diff --git a/note_theme/static/favicon/favicon-32x32.png b/note_theme/static/favicon/favicon-32x32.png new file mode 100644 index 0000000000000000000000000000000000000000..a3d9263f297fd183b2a402677135c0ddd85cfd60 GIT binary patch literal 1482 zcmV;*1vUDKP)Px%TTo0?MNDaNzfusVr>8Ou30xKzbaiv??(P-|6D21b zMKC19#KVAwh(#X=e}RB_FAZ-K5ZKt*v9htO4j7Rs5!ct(;^N|;o}0(U#cVtYo=6OX zgMvdsK)D|mLq9&u8ymA18E9x`zrVg^6A-8x72x3Dif0Cs856+3zPEt}h=zgA&dszF z71`O@y1Kg0&(Fqa43;txw6wF5Iu1Y@49s5+%1#k`BM+!L6OoaSu{{#eoCU|n#&vac z*Vort9Ua=**<&LQvQ!Pb92s693!Xj~hlGT8VP1AOBDJTcClUy&8y?cr)0>xqp(rcR zt3-ni6QU6pii(J#TMD}n8o4PIjEsx5wY2l|^U5t3y}i8SvdBIk3kK<92m+W7|P1Yx;hhs7ZR;tJv=-) zax4voSVz9UzK}o;osyGlDG`8ka!el$nw63Q1q2HR1PTiW84Lx4Vq#oOOMG!_V8x7FV z(7s6#!#fjvD-W?67?L&>!9f-=779NpA}XD2Xo+ znpI1pYFFgcq|vHUb#QEqgLl-dLb0*0*L@0@N)W$;2H>d#uV@OcM-Iz)3aU;Ju84NC zV@bCxE=(mA#)532a&xssNs2%x!HhRyOhcy_6`(C4y0@#sxuW9Ahmnwv#g3E0V&vsAZ#Pw|YSCikV+|uZ)m(a0UKKSPT;~O@p#Hgp~QQ z8L&AM;#T3{kRUz`d3GTa(>zr>b{657h#n19Oasg;=j3WwWhkj7_pH@7V#c&Uc~j5& z4OR~F^G$lD7}#MNAe=pgalyuQ)8|c{!zd}ij;SC^j&Z@yC%2)V&g9NcT~1i|sEBlOb*GCr3p8Ii;FGEqJV|d&P%?r-qqUMRz)CEA&`j`W`cEhx2PC{w2hRk zjC>O>1B0|IJBlX^quAKE)L9vrnA&`&xA?I0%5tIxfgqDkTz?`5gIIgVf&GkrKCZ0j zfg}~C9>>JM!0Wf-#Nyt)&6=2j%&sTE!NB2t`1tA-M^`Tw$5g;71~iq`W96!Y$Ce*D zQpt`zy>hoM>YF`#<*Gh+7VHWH8x}6<>RP&Nj~g>~1)T1Evt~`&H+x4BE(PWjd%I>V zTRhQ{54!>ugNZX|&fK|eqB$pa1?EgReR3ztgS(@0RY!>ho{MknE(I)09SfcSaechcOY6Cgx@G{a;ABePT>%h=S& k#LUDT#0SfONT5nC0O}VJbn-$ql>h($07*qoM6N<$f;w5EXaE2J literal 0 HcmV?d00001 diff --git a/note_theme/static/favicon/favicon.ico b/note_theme/static/favicon/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..53393cda7e0850a26d561567294181c849f5021e GIT binary patch literal 15086 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 Q|AlCi$ZbMBo7HIk578%S-v9sr literal 0 HcmV?d00001 diff --git a/note_theme/static/favicon/mstile-150x150.png b/note_theme/static/favicon/mstile-150x150.png new file mode 100644 index 0000000000000000000000000000000000000000..378274c99391b5f2d3524fe3f6e33c0eed5286a2 GIT binary patch literal 5671 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 literal 0 HcmV?d00001 diff --git a/note_theme/static/favicon/safari-pinned-tab.svg b/note_theme/static/favicon/safari-pinned-tab.svg new file mode 100644 index 00000000..a8425e8a --- /dev/null +++ b/note_theme/static/favicon/safari-pinned-tab.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/note_theme/static/favicon/site.webmanifest b/note_theme/static/favicon/site.webmanifest new file mode 100644 index 00000000..78fcc75f --- /dev/null +++ b/note_theme/static/favicon/site.webmanifest @@ -0,0 +1,19 @@ +{ + "name": "", + "short_name": "", + "icons": [ + { + "src": "/static/favicon/android-chrome-192x192.png", + "sizes": "192x192", + "type": "image/png" + }, + { + "src": "/static/favicon/android-chrome-512x512.png", + "sizes": "512x512", + "type": "image/png" + } + ], + "theme_color": "#ffffff", + "background_color": "#ffffff", + "display": "standalone" +} diff --git a/note_theme/templates/admin/base_site.html b/note_theme/templates/admin/base_site.html new file mode 100644 index 00000000..3ef7f8a5 --- /dev/null +++ b/note_theme/templates/admin/base_site.html @@ -0,0 +1,96 @@ +{% extends "admin/base.html" %} +{% comment %} +SPDX-License-Identifier: GPL-3.0-or-later +{% endcomment %} + +{% load i18n staticfiles %} + +{% block title %}{{ title }} | {{ request.site.name }}{% endblock %} + +{% block branding %} + + + {{ request.site.name }} + + +{% endblock %} + +{% block usertools %} + {% if user.is_authenticated %} +
+ {% block welcome-msg %} + {% trans 'Welcome,' %} + {% firstof user.get_short_name user.get_username %}. + {% endblock %} + {% block userlinks %} + {% if site_url %} + {% trans 'View site' %} / + {% endif %} + {% if available_apps %} + {# When in admin site, list all admin pages and documentation #} + + {% trans 'View admin' %} + + {% for app in available_apps %} + {% for model in app.models %} + {% if model.admin_url %} + {{ model.name }} + {% endif %} + {% endfor %} + {% endfor %} + {% if user.is_active and user.is_superuser %} + {% url 'django-admindocs-docroot' as docsroot %} + {% if docsroot %} + {% trans 'Documentation' %} + {% endif %} + {% endif %} + + / + {% elif user.is_staff %} + {# When not in admin site, but user is staff then add a link #} + {% trans 'View admin' %} / + {% endif %} + {% trans 'Log out' %} + {% endblock %} +
+ {% endif %} +{% endblock %} + +{% block extrastyle %} + + + {# Favicon #} + + + + + + + + + +{% endblock %} + +{% block footer %} + {% if not is_popup %} + + {% endif %} +{% endblock %} diff --git a/note_theme/templates/registration/logged_out.html b/note_theme/templates/registration/logged_out.html new file mode 100644 index 00000000..3ecc65e2 --- /dev/null +++ b/note_theme/templates/registration/logged_out.html @@ -0,0 +1,11 @@ +{% extends "registration/logged_out.html" %} +{% comment %} +SPDX-License-Identifier: GPL-3.0-or-later +{% endcomment %} +{% load i18n %} + +{% block breadcrumbs %} + +{% endblock %} diff --git a/note_theme/templates/registration/password_change_done.html b/note_theme/templates/registration/password_change_done.html new file mode 100644 index 00000000..d42fbfd9 --- /dev/null +++ b/note_theme/templates/registration/password_change_done.html @@ -0,0 +1,11 @@ +{% extends "registration/password_change_done.html" %} +{% comment %} +SPDX-License-Identifier: GPL-3.0-or-later +{% endcomment %} +{% load i18n %} + +{% block breadcrumbs %} + +{% endblock %} diff --git a/note_theme/templates/registration/password_change_form.html b/note_theme/templates/registration/password_change_form.html new file mode 100644 index 00000000..07ab38c9 --- /dev/null +++ b/note_theme/templates/registration/password_change_form.html @@ -0,0 +1,11 @@ +{% extends "registration/password_change_form.html" %} +{% comment %} +SPDX-License-Identifier: GPL-3.0-or-later +{% endcomment %} +{% load i18n %} + +{% block breadcrumbs %} + +{% endblock %} diff --git a/note_theme/templates/registration/password_reset_complete.html b/note_theme/templates/registration/password_reset_complete.html new file mode 100644 index 00000000..f0ec4b8f --- /dev/null +++ b/note_theme/templates/registration/password_reset_complete.html @@ -0,0 +1,11 @@ +{% extends "registration/password_reset_complete.html" %} +{% comment %} +SPDX-License-Identifier: GPL-3.0-or-later +{% endcomment %} +{% load i18n %} + +{% block breadcrumbs %} + +{% endblock %} diff --git a/note_theme/templates/registration/password_reset_confirm.html b/note_theme/templates/registration/password_reset_confirm.html new file mode 100644 index 00000000..62a761d5 --- /dev/null +++ b/note_theme/templates/registration/password_reset_confirm.html @@ -0,0 +1,11 @@ +{% extends "registration/password_reset_confirm.html" %} +{% comment %} +SPDX-License-Identifier: GPL-3.0-or-later +{% endcomment %} +{% load i18n %} + +{% block breadcrumbs %} + +{% endblock %} diff --git a/note_theme/templates/registration/password_reset_done.html b/note_theme/templates/registration/password_reset_done.html new file mode 100644 index 00000000..ea67e596 --- /dev/null +++ b/note_theme/templates/registration/password_reset_done.html @@ -0,0 +1,11 @@ +{% extends "registration/password_reset_done.html" %} +{% comment %} +SPDX-License-Identifier: GPL-3.0-or-later +{% endcomment %} +{% load i18n %} + +{% block breadcrumbs %} + +{% endblock %} diff --git a/note_theme/templates/registration/password_reset_email.html b/note_theme/templates/registration/password_reset_email.html new file mode 100644 index 00000000..f43d80c3 --- /dev/null +++ b/note_theme/templates/registration/password_reset_email.html @@ -0,0 +1,13 @@ +{% load i18n %}{% autoescape off %} +{% blocktrans %}You're receiving this email because you requested a password reset for your user account at {{ site_name }}.{% endblocktrans %} + +{% trans "Please go to the following page and choose a new password:" %} +{% block reset_link %} +{{ protocol }}://{{ domain }}{% url 'password_reset_confirm' uidb64=uid token=token %} +{% endblock %} + +{% trans "Thanks for using our site!" %} + +{% blocktrans %}The {{ site_name }} team{% endblocktrans %} + +{% endautoescape %} diff --git a/note_theme/templates/registration/password_reset_form.html b/note_theme/templates/registration/password_reset_form.html new file mode 100644 index 00000000..865d5160 --- /dev/null +++ b/note_theme/templates/registration/password_reset_form.html @@ -0,0 +1,11 @@ +{% extends "registration/password_reset_form.html" %} +{% comment %} +SPDX-License-Identifier: GPL-3.0-or-later +{% endcomment %} +{% load i18n %} + +{% block breadcrumbs %} + +{% endblock %} diff --git a/note_theme/tests/__init__.py b/note_theme/tests/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/note_theme/tests/test_templates.py b/note_theme/tests/test_templates.py new file mode 100644 index 00000000..6d00c147 --- /dev/null +++ b/note_theme/tests/test_templates.py @@ -0,0 +1,44 @@ +# -*- mode: python; coding: utf-8 -*- +# SPDX-License-Identifier: GPL-3.0-or-later + +from django.contrib.auth.models import User +from django.test import TestCase + +""" +Test that every themed page still works +""" + + +class TemplateLoggedOutTests(TestCase): + def test_login_page(self): + response = self.client.get('/admin/login/') + self.assertEqual(response.status_code, 200) + + +class TemplateLoggedInTests(TestCase): + def setUp(self): + self.user = User.objects.create_superuser( + username="admin", + password="adminadmin", + email="admin@example.com", + ) + self.client.force_login(self.user) + + def test_login_page(self): + """ + Login page should redirect + """ + response = self.client.get('/admin/login/') + self.assertEqual(response.status_code, 302) + + def test_admin_index(self): + response = self.client.get('/admin/') + self.assertEqual(response.status_code, 200) + + def test_accounts_password_reset(self): + response = self.client.get('/accounts/password_reset/') + self.assertEqual(response.status_code, 200) + + def test_logout_page(self): + response = self.client.get('/accounts/logout/') + self.assertEqual(response.status_code, 200) diff --git a/tox.ini b/tox.ini new file mode 100644 index 00000000..615a2701 --- /dev/null +++ b/tox.ini @@ -0,0 +1,49 @@ +[tox] +envlist = py36,py37,linters +skipsdist = True + +[testenv] +basepython = python3 +deps = + -r{toxinidir}/requirements.txt + coverage +commands = + coverage run ./manage.py test {posargs} + coverage report -m + +[testenv:pre-commit] +deps = pre-commit +commands = + pre-commit run --all-files --show-diff-on-failure + +[testenv:linters] +deps = + -r{toxinidir}/requirements.txt + flake8 + flake8-colors + flake8-import-order + flake8-typing-imports + pep8-naming + pyflakes + pylint +commands = + flake8 note_* + pylint . + +[flake8] +ignore = D203, W503, E203 +exclude = + .tox, + .git, + __pycache__, + build, + dist, + *.pyc, + *.egg-info, + .cache, + .eggs +max-complexity = 10 +import-order-style = google +application-import-names = flake8 +format = ${cyan}%(path)s${reset}:${yellow_bold}%(row)d${reset}:${green_bold}%(col)d${reset}: ${red_bold}%(code)s${reset} %(text)s +