Compare commits
7 commits
3c6da6a49a
...
8311d12d20
Author | SHA1 | Date | |
---|---|---|---|
8311d12d20 | |||
a91613cbd3 | |||
2a2175e31a | |||
1d9fa011a3 | |||
3698d46649 | |||
2aeccd44be | |||
9af92175a9 |
16 changed files with 218 additions and 180 deletions
|
@ -1,3 +1,4 @@
|
|||
DEBUG=true
|
||||
SESSION_KEY=debug
|
||||
CSRF_KEY=debug
|
||||
DB_HOST=localhost
|
||||
|
|
5
Makefile
5
Makefile
|
@ -1,5 +1,6 @@
|
|||
dev:
|
||||
DEBUG="true" python3 -m uvicorn main:app --reload
|
||||
python3 -m dotenv -f .env_debug run \
|
||||
python3 -m uvicorn main:app --reload
|
||||
|
||||
prod:
|
||||
python3 -m uvicorn main:app
|
||||
|
@ -16,6 +17,6 @@ docker:
|
|||
|
||||
clean:
|
||||
rm -rf app/__pycache__
|
||||
rm -rf app/paths/__pycache__
|
||||
rm -rf app/*/__pycache__
|
||||
rm -rf __pycache__
|
||||
rm -rf .mypy_cache
|
||||
|
|
69
README.md
69
README.md
|
@ -14,6 +14,38 @@ Includes Jinja, WTForms, MySQL ORM and Docker.
|
|||
- Dockerfile, Docker-Compose
|
||||
|
||||
|
||||
## Usage
|
||||
1. Create a repository from this template
|
||||
2. For debugging, change the database connection parameters
|
||||
in `.env_debug` file correspoding to the configuration
|
||||
of MariaDB/MySQL server on your PC
|
||||
3. Edit app [paths](#paths),
|
||||
[custom error pages](#custom-error-pages)
|
||||
and [forms](#wtforms)
|
||||
as explained in the "Structure" section
|
||||
4. Create your own Jinja templates in the `templates/` directory,
|
||||
editing `base.html` and inheriting other templates from it is recommended
|
||||
(see `index,table,admin.html` for examples)
|
||||
5. Edit or remove CSS and JS files in `static/`
|
||||
6. Edit `sql/models,schemas,crud.py`
|
||||
corresponding to your database structure
|
||||
as explained below ([Structure > Database](#database))
|
||||
7. Check if `Makefile`, `Dockerfile`, `docker-compose.yml` are correct
|
||||
8. Run the formatter and linters (`make format`, then `make check`)
|
||||
9. Build a docker image and [publish](#publishing-app) it
|
||||
|
||||
### Makefile
|
||||
Make commands:
|
||||
|Command|Description|
|
||||
|:-----:|:----------|
|
||||
|`make format`|Format the code using AutoPEP8|
|
||||
|`make check`|Check the code with linters (MyPy, Pylint)|
|
||||
|`make dev`|Run the app in development mode|
|
||||
|`make prod`|Run a production server|
|
||||
|`make docker`|Build a docker image from `Dockerfile`|
|
||||
|`make clean`|Clean all cache|
|
||||
|
||||
|
||||
## Structure
|
||||
|
||||
### Configuration
|
||||
|
@ -27,10 +59,9 @@ Includes Jinja, WTForms, MySQL ORM and Docker.
|
|||
#### The main config loaded by `app/common.py`:
|
||||
- `templates_dir`, `static_dir` contain the paths
|
||||
to templates and static files directories correspondingly
|
||||
- `debug_env` is a path to `.env_debug`
|
||||
- `is_debug` is True when DEBUG env variable is set,
|
||||
and then `.env_debug` is loaded automatically
|
||||
- `settings` (pydantic.BaseSettings):
|
||||
- `debug` means the application is running
|
||||
in a development environment
|
||||
- `session_key`, `csrf_key` are secret keys
|
||||
for WTForms CSRF protection;
|
||||
generated with secrets.token_urlsafe
|
||||
|
@ -66,7 +97,7 @@ You can
|
|||
copying the contents of `pages.py`
|
||||
|
||||
> **Note**
|
||||
> In the paths files FastAPI's decorators
|
||||
> In the paths files, FastAPI's decorators
|
||||
are called with `@self.app.`, not just `@app.`
|
||||
|
||||
In case of deleteing/renaming/creating any paths files,
|
||||
|
@ -92,36 +123,6 @@ TODO
|
|||
TODO
|
||||
|
||||
|
||||
## Usage
|
||||
|
||||
<!--
|
||||
1. Create a repository from this template
|
||||
2. For debugging, open `.env_debug` file and
|
||||
set host, user, password corresponding to
|
||||
the configuration of MySQL/MariaDB on your PC
|
||||
3. Edit `paths/pages.py`: add your own paths
|
||||
in the `add_paths` method
|
||||
4. Create your own Jinja templates in `templates/` directory,
|
||||
I recommend to edit `base.html` and inherit other templates from it
|
||||
5. Edit and rename `forms/users.py`, it contains WTForms classes
|
||||
6. Customize error pages and add your own paths ...
|
||||
7. Edit `db/schema.sql` corresponding to your database structure
|
||||
8. Check `Makefile`, `Dockerfile`, `docker-compose.yml`
|
||||
9. Run formatter and linters (`make format`, then `make check`)
|
||||
-->
|
||||
|
||||
### Makefile
|
||||
Make commands:
|
||||
|Command|Description|
|
||||
|:-----:|:----------|
|
||||
|`make format`|Format the code using AutoPEP8|
|
||||
|`make check`|Check the code with linters (MyPy, Pylint)|
|
||||
|`make dev`|Run the app in development mode|
|
||||
|`make prod`|Run a production server|
|
||||
|`make docker`|Build a docker image from `Dockerfile`|
|
||||
|`make clean`|Clean all cache|
|
||||
|
||||
|
||||
## Helper functions
|
||||
|
||||
### `respond.py`
|
||||
|
|
|
@ -1,13 +1,11 @@
|
|||
import os
|
||||
import secrets
|
||||
from pathlib import Path
|
||||
|
||||
from dotenv import load_dotenv
|
||||
|
||||
from fastapi.templating import Jinja2Templates
|
||||
from pydantic import BaseSettings
|
||||
|
||||
|
||||
# Directories
|
||||
file_dir = Path(__file__).parent
|
||||
templates_dir = str(
|
||||
file_dir.parent / 'templates'
|
||||
|
@ -15,23 +13,19 @@ templates_dir = str(
|
|||
static_dir = str(
|
||||
file_dir.parent / 'static'
|
||||
)
|
||||
debug_env = str(
|
||||
file_dir.parent / '.env_debug'
|
||||
)
|
||||
|
||||
|
||||
is_debug = bool(os.getenv('DEBUG'))
|
||||
if is_debug:
|
||||
load_dotenv(debug_env)
|
||||
|
||||
|
||||
# Main configuration
|
||||
class Settings(BaseSettings):
|
||||
debug: bool = False
|
||||
session_key: str = secrets.token_hex(32)
|
||||
csrf_key: str = secrets.token_hex(32)
|
||||
|
||||
|
||||
settings = Settings()
|
||||
|
||||
|
||||
# Jinja templates handler
|
||||
templates = Jinja2Templates(
|
||||
directory=templates_dir,
|
||||
)
|
||||
|
|
|
@ -25,5 +25,5 @@ async def get_form(
|
|||
Returns:
|
||||
StarletteForm instance
|
||||
"""
|
||||
|
||||
|
||||
return await form.from_formdata(request=req)
|
||||
|
|
12
app/main.py
12
app/main.py
|
@ -7,7 +7,7 @@ from starlette.middleware.sessions import SessionMiddleware
|
|||
from starlette_wtf import CSRFProtectMiddleware
|
||||
|
||||
from . import common
|
||||
from .sql import db
|
||||
from . import sql
|
||||
|
||||
from .paths import Paths
|
||||
# Add your paths below
|
||||
|
@ -22,16 +22,24 @@ paths: List[Type[Paths]] = [
|
|||
]
|
||||
|
||||
|
||||
db.Base.metadata.create_all(bind=db.engine)
|
||||
# Initialize SQL database
|
||||
sql.Base.metadata.create_all(bind=sql.engine)
|
||||
|
||||
# Create app
|
||||
app = FastAPI()
|
||||
|
||||
# Mount static files server
|
||||
app.mount(
|
||||
'/static',
|
||||
StaticFiles(directory=common.static_dir),
|
||||
name='static',
|
||||
)
|
||||
|
||||
# Add paths
|
||||
for p in paths:
|
||||
p(app).add_paths()
|
||||
|
||||
# Add WTForms CSRF protection middlewares
|
||||
app.add_middleware(
|
||||
SessionMiddleware,
|
||||
secret_key=common.settings.session_key,
|
||||
|
|
|
@ -17,7 +17,7 @@ class Paths(abc.ABC):
|
|||
"""
|
||||
|
||||
self.app = app
|
||||
|
||||
|
||||
@abc.abstractmethod
|
||||
def add_paths(self) -> None:
|
||||
"""Add paths to the FastAPI application"""
|
||||
|
|
|
@ -20,9 +20,10 @@ class ErrorsPaths(Paths):
|
|||
|
||||
def add_paths(self) -> None:
|
||||
|
||||
# For each HTTP code specified above
|
||||
for code in codes:
|
||||
self.add_handler(code)
|
||||
|
||||
|
||||
def add_handler(self, code: int) -> None:
|
||||
"""Adds an error handler to FastAPI app.
|
||||
Only for internal use!
|
||||
|
@ -31,14 +32,19 @@ class ErrorsPaths(Paths):
|
|||
code (int): HTTP error code
|
||||
"""
|
||||
|
||||
# Jinja template file name
|
||||
# e.g. 404.html for 404 code
|
||||
file = Path(common.templates_dir) / f'{code}.html'
|
||||
|
||||
# Exit from the function
|
||||
# if the template does not exist
|
||||
if not file.exists():
|
||||
return
|
||||
|
||||
@self.app.exception_handler(code)
|
||||
async def handler(req: Request, exc: HTTPException) -> Response:
|
||||
|
||||
# Respond with the template
|
||||
return respond.with_tmpl(
|
||||
f'{code}.html',
|
||||
code=code,
|
||||
|
|
|
@ -9,7 +9,7 @@ from starlette_wtf import csrf_protect
|
|||
|
||||
from . import Paths
|
||||
from .. import respond
|
||||
from ..sql import db
|
||||
from .. import sql
|
||||
from ..sql import crud
|
||||
from ..sql import schemas
|
||||
from ..forms import get_form
|
||||
|
@ -26,7 +26,7 @@ class TablePaths(Paths):
|
|||
def list_users(
|
||||
req: Request,
|
||||
page: int = 0,
|
||||
db: Session = Depends(db.get_db)) -> Response:
|
||||
db: Session = Depends(sql.get_db)) -> Response:
|
||||
|
||||
return respond.with_tmpl(
|
||||
'table.html',
|
||||
|
@ -43,7 +43,7 @@ class TablePaths(Paths):
|
|||
@csrf_protect
|
||||
async def add_form(
|
||||
req: Request,
|
||||
db_s: Session = Depends(db.get_db)) -> Response:
|
||||
db_s: Session = Depends(sql.get_db)) -> Response:
|
||||
|
||||
form = await get_form(AddUserForm, req)
|
||||
|
||||
|
@ -51,7 +51,7 @@ class TablePaths(Paths):
|
|||
|
||||
if form.pswd.data != '1234':
|
||||
return respond.with_text('Incorrect password')
|
||||
|
||||
|
||||
crud.create_user(
|
||||
db=db_s,
|
||||
user=schemas.UserCreate(
|
||||
|
|
|
@ -16,12 +16,12 @@ from .common import templates
|
|||
def with_redirect(
|
||||
url: str = '/',
|
||||
code: int = 302,
|
||||
*args, **kwargs) -> RedirectResponse:
|
||||
**kwargs) -> RedirectResponse:
|
||||
"""Return a redirect to the page specified in `url`.
|
||||
By default, code is 302 so method is changed to GET.
|
||||
To leave the same HTTP method, use 307 status code
|
||||
or call `with_redirect_307` function.
|
||||
`args` and `kwargs` are passed directly
|
||||
`kwargs` are passed directly
|
||||
to the Response contructor
|
||||
|
||||
Args:
|
||||
|
@ -35,16 +35,16 @@ def with_redirect(
|
|||
return RedirectResponse(
|
||||
url=url,
|
||||
status_code=code,
|
||||
*args, **kwargs,
|
||||
**kwargs,
|
||||
)
|
||||
|
||||
|
||||
def with_text(
|
||||
content: str,
|
||||
code: int = 200,
|
||||
*args, **kwargs) -> PlainTextResponse:
|
||||
**kwargs) -> PlainTextResponse:
|
||||
"""Return a plain text to the user.
|
||||
`args` and `kwargs` are passed directly
|
||||
`kwargs` are passed directly
|
||||
to the Response contructor
|
||||
|
||||
Args:
|
||||
|
@ -58,7 +58,7 @@ def with_text(
|
|||
return PlainTextResponse(
|
||||
content=content,
|
||||
status_code=code,
|
||||
*args, **kwargs,
|
||||
**kwargs,
|
||||
)
|
||||
|
||||
|
||||
|
@ -117,10 +117,10 @@ def with_file(
|
|||
path: os.PathLike,
|
||||
mime: Optional[str] = None,
|
||||
code: int = 200,
|
||||
*args, **kwargs) -> FileResponse:
|
||||
**kwargs) -> FileResponse:
|
||||
"""Send the file specified in `path`
|
||||
automatically guessing its mimetype if `mime` is None.
|
||||
`args` and `kwargs` are passed directly
|
||||
`kwargs` are passed directly
|
||||
to the Response contructor
|
||||
|
||||
Args:
|
||||
|
@ -135,11 +135,11 @@ def with_file(
|
|||
return FileResponse(
|
||||
path=path,
|
||||
media_type=(
|
||||
mime or
|
||||
mime or
|
||||
mimetypes.guess_type(path)[0]
|
||||
),
|
||||
status_code=code,
|
||||
*args, **kwargs,
|
||||
**kwargs,
|
||||
)
|
||||
|
||||
|
||||
|
|
|
@ -3,12 +3,14 @@ from typing import AsyncGenerator
|
|||
from pydantic import BaseSettings
|
||||
|
||||
from sqlalchemy import create_engine
|
||||
from sqlalchemy_utils import database_exists
|
||||
from sqlalchemy_utils import create_database
|
||||
from sqlalchemy.orm import Session, sessionmaker
|
||||
from sqlalchemy.ext.declarative import declarative_base
|
||||
|
||||
from sqlalchemy_utils import database_exists
|
||||
from sqlalchemy_utils import create_database
|
||||
|
||||
|
||||
# Database configuration
|
||||
class SqlSettings(BaseSettings):
|
||||
db_host: str = '${REPO_NAME_SNAKE}_db'
|
||||
db_port: int = 3306
|
||||
|
@ -16,26 +18,36 @@ class SqlSettings(BaseSettings):
|
|||
db_password: str = ''
|
||||
db_database: str = '${REPO_NAME_SNAKE}'
|
||||
|
||||
|
||||
sql_settings = SqlSettings()
|
||||
|
||||
# DB connection URL
|
||||
# pylint: disable=consider-using-f-string
|
||||
db_url = (
|
||||
'mysql://{db_user}:{db_password}@'
|
||||
'{db_host}:{db_port}/{db_database}'
|
||||
).format(**sql_settings.dict())
|
||||
# pylint: enable=consider-using-f-string
|
||||
|
||||
|
||||
# SQLAlchemy engine object
|
||||
engine = create_engine(db_url)
|
||||
|
||||
# Create DB if not exists
|
||||
if not database_exists(db_url):
|
||||
create_database(db_url)
|
||||
|
||||
# SQLAlchemy Session object
|
||||
SessionLocal = sessionmaker(
|
||||
autoflush=False,
|
||||
bind=engine,
|
||||
)
|
||||
|
||||
# SQLAlchemy Base object
|
||||
Base = declarative_base()
|
||||
|
||||
|
||||
# FastAPI dependency
|
||||
async def get_db() -> AsyncGenerator[Session, None]:
|
||||
"""FastAPI dependency
|
||||
returning database Session object.
|
|
@ -6,6 +6,7 @@ from . import models
|
|||
from . import schemas
|
||||
|
||||
|
||||
# SELECT * from users LIMIT 1
|
||||
def get_user(
|
||||
db: Session,
|
||||
user_id: int) -> Optional[models.User]:
|
||||
|
@ -16,6 +17,7 @@ def get_user(
|
|||
.first()
|
||||
|
||||
|
||||
# SELECT * from users
|
||||
def get_users(
|
||||
db: Session,
|
||||
skip: int = 0,
|
||||
|
@ -28,6 +30,7 @@ def get_users(
|
|||
.all()
|
||||
|
||||
|
||||
# INSERT INTO users
|
||||
def create_user(
|
||||
db: Session,
|
||||
user: schemas.UserCreate) -> models.User:
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
from sqlalchemy import Column, String, Integer
|
||||
|
||||
from .db import Base
|
||||
from . import Base
|
||||
|
||||
|
||||
class User(Base):
|
||||
|
|
|
@ -1,12 +1,16 @@
|
|||
from pydantic import BaseModel
|
||||
from pydantic import BaseModel # pylint: disable=no-name-in-module
|
||||
|
||||
|
||||
# Pydantic class for
|
||||
# INSERT queries on a User model
|
||||
class UserCreate(BaseModel):
|
||||
email: str
|
||||
name: str
|
||||
age: int
|
||||
|
||||
|
||||
# Pydantic class for
|
||||
# SELECT responses with User model(-s)
|
||||
class User(UserCreate):
|
||||
id: int
|
||||
|
||||
|
|
4
mypy.ini
Normal file
4
mypy.ini
Normal file
|
@ -0,0 +1,4 @@
|
|||
[mypy]
|
||||
show_error_codes = True
|
||||
ignore_missing_imports = True
|
||||
warn_redundant_casts = True
|
224
pylintrc
224
pylintrc
|
@ -1,5 +1,6 @@
|
|||
[MAIN]
|
||||
analyse-fallback-blocks=no
|
||||
clear-cache-post-run=no
|
||||
extension-pkg-allow-list=
|
||||
extension-pkg-whitelist=
|
||||
fail-on=
|
||||
|
@ -17,113 +18,6 @@ recursive=no
|
|||
suggestion-mode=yes
|
||||
unsafe-load-any-extension=no
|
||||
|
||||
[REPORTS]
|
||||
evaluation=max(0, 0 if fatal else 10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10))
|
||||
msg-template=
|
||||
reports=no
|
||||
score=yes
|
||||
|
||||
[MESSAGES CONTROL]
|
||||
confidence=HIGH,
|
||||
CONTROL_FLOW,
|
||||
INFERENCE,
|
||||
INFERENCE_FAILURE,
|
||||
UNDEFINED
|
||||
disable=raw-checker-failed,
|
||||
bad-inline-option,
|
||||
locally-disabled,
|
||||
file-ignored,
|
||||
suppressed-message,
|
||||
useless-suppression,
|
||||
deprecated-pragma,
|
||||
use-symbolic-message-instead
|
||||
enable=c-extension-no-member
|
||||
|
||||
[SIMILARITIES]
|
||||
ignore-comments=yes
|
||||
ignore-docstrings=yes
|
||||
ignore-imports=yes
|
||||
ignore-signatures=yes
|
||||
min-similarity-lines=4
|
||||
|
||||
[MISCELLANEOUS]
|
||||
notes=FIXME,
|
||||
XXX,
|
||||
TODO
|
||||
notes-rgx=
|
||||
|
||||
[DESIGN]
|
||||
exclude-too-few-public-methods=
|
||||
ignored-parents=
|
||||
max-args=5
|
||||
max-attributes=7
|
||||
max-bool-expr=5
|
||||
max-branches=12
|
||||
max-locals=15
|
||||
max-parents=7
|
||||
max-public-methods=20
|
||||
max-returns=6
|
||||
max-statements=50
|
||||
min-public-methods=1
|
||||
|
||||
[STRING]
|
||||
check-quote-consistency=no
|
||||
check-str-concat-over-line-jumps=no
|
||||
|
||||
[CLASSES]
|
||||
check-protected-access-in-special-methods=no
|
||||
defining-attr-methods=__init__,
|
||||
__new__,
|
||||
setUp,
|
||||
__post_init__
|
||||
exclude-protected=_asdict,
|
||||
_fields,
|
||||
_replace,
|
||||
_source,
|
||||
_make
|
||||
valid-classmethod-first-arg=cls
|
||||
valid-metaclass-classmethod-first-arg=cls
|
||||
|
||||
[FORMAT]
|
||||
expected-line-ending-format=
|
||||
ignore-long-lines=^\s*(# )?<?https?://\S+>?$
|
||||
indent-after-paren=4
|
||||
indent-string=' '
|
||||
max-line-length=100
|
||||
max-module-lines=1000
|
||||
single-line-class-stmt=no
|
||||
single-line-if-stmt=no
|
||||
|
||||
[IMPORTS]
|
||||
allow-any-import-level=
|
||||
allow-wildcard-with-all=no
|
||||
deprecated-modules=
|
||||
ext-import-graph=
|
||||
import-graph=
|
||||
int-import-graph=
|
||||
known-standard-library=
|
||||
known-third-party=enchant
|
||||
preferred-modules=
|
||||
|
||||
[VARIABLES]
|
||||
additional-builtins=
|
||||
allow-global-unused-variables=yes
|
||||
allowed-redefined-builtins=
|
||||
callbacks=cb_,
|
||||
_cb
|
||||
dummy-variables-rgx=_+$|(_[a-zA-Z0-9_]*[a-zA-Z0-9]+?$)|dummy|^ignored_|^unused_
|
||||
ignored-argument-names=_.*|^ignored_|^unused_
|
||||
init-import=no
|
||||
redefining-builtins-modules=six.moves,past.builtins,future.builtins,builtins,io
|
||||
|
||||
[LOGGING]
|
||||
logging-format-style=old
|
||||
logging-modules=logging
|
||||
|
||||
[EXCEPTIONS]
|
||||
overgeneral-exceptions=BaseException,
|
||||
Exception
|
||||
|
||||
[BASIC]
|
||||
argument-naming-style=snake_case
|
||||
attr-naming-style=snake_case
|
||||
|
@ -158,6 +52,105 @@ no-docstring-rgx=^_
|
|||
property-classes=abc.abstractproperty
|
||||
variable-naming-style=snake_case
|
||||
|
||||
[CLASSES]
|
||||
check-protected-access-in-special-methods=no
|
||||
defining-attr-methods=__init__,
|
||||
__new__,
|
||||
setUp,
|
||||
__post_init__
|
||||
exclude-protected=_asdict,
|
||||
_fields,
|
||||
_replace,
|
||||
_source,
|
||||
_make
|
||||
valid-classmethod-first-arg=cls
|
||||
valid-metaclass-classmethod-first-arg=mcs
|
||||
|
||||
[DESIGN]
|
||||
exclude-too-few-public-methods=
|
||||
ignored-parents=
|
||||
max-args=5
|
||||
max-attributes=7
|
||||
max-bool-expr=5
|
||||
max-branches=12
|
||||
max-locals=15
|
||||
max-parents=7
|
||||
max-public-methods=20
|
||||
max-returns=6
|
||||
max-statements=50
|
||||
min-public-methods=0
|
||||
|
||||
[EXCEPTIONS]
|
||||
overgeneral-exceptions=builtins.BaseException,builtins.Exception
|
||||
|
||||
[FORMAT]
|
||||
expected-line-ending-format=
|
||||
ignore-long-lines=^\s*(# )?<?https?://\S+>?$
|
||||
indent-after-paren=4
|
||||
indent-string=' '
|
||||
max-line-length=100
|
||||
max-module-lines=1000
|
||||
single-line-class-stmt=no
|
||||
single-line-if-stmt=no
|
||||
|
||||
[IMPORTS]
|
||||
allow-any-import-level=
|
||||
allow-reexport-from-package=no
|
||||
allow-wildcard-with-all=no
|
||||
deprecated-modules=
|
||||
ext-import-graph=
|
||||
import-graph=
|
||||
int-import-graph=
|
||||
known-standard-library=
|
||||
known-third-party=enchant
|
||||
preferred-modules=
|
||||
|
||||
[LOGGING]
|
||||
logging-format-style=old
|
||||
logging-modules=logging
|
||||
|
||||
[MESSAGES CONTROL]
|
||||
confidence=HIGH,
|
||||
CONTROL_FLOW,
|
||||
INFERENCE,
|
||||
INFERENCE_FAILURE,
|
||||
UNDEFINED
|
||||
disable=raw-checker-failed,
|
||||
bad-inline-option,
|
||||
locally-disabled,
|
||||
file-ignored,
|
||||
suppressed-message,
|
||||
useless-suppression,
|
||||
deprecated-pragma,
|
||||
use-symbolic-message-instead
|
||||
enable=c-extension-no-member
|
||||
|
||||
[METHOD_ARGS]
|
||||
timeout-methods=requests.api.delete,requests.api.get,requests.api.head,requests.api.options,requests.api.patch,requests.api.post,requests.api.put,requests.api.request
|
||||
|
||||
[MISCELLANEOUS]
|
||||
notes=FIXME,
|
||||
XXX,
|
||||
TODO
|
||||
notes-rgx=
|
||||
|
||||
[REFACTORING]
|
||||
max-nested-blocks=5
|
||||
never-returning-functions=sys.exit,argparse.parse_error
|
||||
|
||||
[REPORTS]
|
||||
evaluation=max(0, 0 if fatal else 10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10))
|
||||
msg-template=
|
||||
reports=no
|
||||
score=yes
|
||||
|
||||
[SIMILARITIES]
|
||||
ignore-comments=yes
|
||||
ignore-docstrings=yes
|
||||
ignore-imports=yes
|
||||
ignore-signatures=yes
|
||||
min-similarity-lines=4
|
||||
|
||||
[SPELLING]
|
||||
max-spelling-suggestions=4
|
||||
spelling-dict=
|
||||
|
@ -166,6 +159,10 @@ spelling-ignore-words=
|
|||
spelling-private-dict-file=
|
||||
spelling-store-unknown-words=no
|
||||
|
||||
[STRING]
|
||||
check-quote-consistency=no
|
||||
check-str-concat-over-line-jumps=no
|
||||
|
||||
[TYPECHECK]
|
||||
contextmanager-decorators=contextlib.contextmanager
|
||||
generated-members=
|
||||
|
@ -182,6 +179,13 @@ missing-member-max-choices=1
|
|||
mixin-class-rgx=.*[Mm]ixin
|
||||
signature-mutators=
|
||||
|
||||
[REFACTORING]
|
||||
max-nested-blocks=5
|
||||
never-returning-functions=sys.exit,argparse.parse_error
|
||||
[VARIABLES]
|
||||
additional-builtins=
|
||||
allow-global-unused-variables=yes
|
||||
allowed-redefined-builtins=
|
||||
callbacks=cb_,
|
||||
_cb
|
||||
dummy-variables-rgx=_+$|(_[a-zA-Z0-9_]*[a-zA-Z0-9]+?$)|dummy|^ignored_|^unused_
|
||||
ignored-argument-names=_.*|^ignored_|^unused_
|
||||
init-import=no
|
||||
redefining-builtins-modules=six.moves,past.builtins,future.builtins,builtins,io
|
||||
|
|
Loading…
Add table
Reference in a new issue