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
|
SESSION_KEY=debug
|
||||||
CSRF_KEY=debug
|
CSRF_KEY=debug
|
||||||
DB_HOST=localhost
|
DB_HOST=localhost
|
||||||
|
|
5
Makefile
5
Makefile
|
@ -1,5 +1,6 @@
|
||||||
dev:
|
dev:
|
||||||
DEBUG="true" python3 -m uvicorn main:app --reload
|
python3 -m dotenv -f .env_debug run \
|
||||||
|
python3 -m uvicorn main:app --reload
|
||||||
|
|
||||||
prod:
|
prod:
|
||||||
python3 -m uvicorn main:app
|
python3 -m uvicorn main:app
|
||||||
|
@ -16,6 +17,6 @@ docker:
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -rf app/__pycache__
|
rm -rf app/__pycache__
|
||||||
rm -rf app/paths/__pycache__
|
rm -rf app/*/__pycache__
|
||||||
rm -rf __pycache__
|
rm -rf __pycache__
|
||||||
rm -rf .mypy_cache
|
rm -rf .mypy_cache
|
||||||
|
|
69
README.md
69
README.md
|
@ -14,6 +14,38 @@ Includes Jinja, WTForms, MySQL ORM and Docker.
|
||||||
- Dockerfile, Docker-Compose
|
- 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
|
## Structure
|
||||||
|
|
||||||
### Configuration
|
### Configuration
|
||||||
|
@ -27,10 +59,9 @@ Includes Jinja, WTForms, MySQL ORM and Docker.
|
||||||
#### The main config loaded by `app/common.py`:
|
#### The main config loaded by `app/common.py`:
|
||||||
- `templates_dir`, `static_dir` contain the paths
|
- `templates_dir`, `static_dir` contain the paths
|
||||||
to templates and static files directories correspondingly
|
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):
|
- `settings` (pydantic.BaseSettings):
|
||||||
|
- `debug` means the application is running
|
||||||
|
in a development environment
|
||||||
- `session_key`, `csrf_key` are secret keys
|
- `session_key`, `csrf_key` are secret keys
|
||||||
for WTForms CSRF protection;
|
for WTForms CSRF protection;
|
||||||
generated with secrets.token_urlsafe
|
generated with secrets.token_urlsafe
|
||||||
|
@ -66,7 +97,7 @@ You can
|
||||||
copying the contents of `pages.py`
|
copying the contents of `pages.py`
|
||||||
|
|
||||||
> **Note**
|
> **Note**
|
||||||
> In the paths files FastAPI's decorators
|
> In the paths files, FastAPI's decorators
|
||||||
are called with `@self.app.`, not just `@app.`
|
are called with `@self.app.`, not just `@app.`
|
||||||
|
|
||||||
In case of deleteing/renaming/creating any paths files,
|
In case of deleteing/renaming/creating any paths files,
|
||||||
|
@ -92,36 +123,6 @@ TODO
|
||||||
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
|
## Helper functions
|
||||||
|
|
||||||
### `respond.py`
|
### `respond.py`
|
||||||
|
|
|
@ -1,13 +1,11 @@
|
||||||
import os
|
|
||||||
import secrets
|
import secrets
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
from dotenv import load_dotenv
|
|
||||||
|
|
||||||
from fastapi.templating import Jinja2Templates
|
from fastapi.templating import Jinja2Templates
|
||||||
from pydantic import BaseSettings
|
from pydantic import BaseSettings
|
||||||
|
|
||||||
|
|
||||||
|
# Directories
|
||||||
file_dir = Path(__file__).parent
|
file_dir = Path(__file__).parent
|
||||||
templates_dir = str(
|
templates_dir = str(
|
||||||
file_dir.parent / 'templates'
|
file_dir.parent / 'templates'
|
||||||
|
@ -15,23 +13,19 @@ templates_dir = str(
|
||||||
static_dir = str(
|
static_dir = str(
|
||||||
file_dir.parent / 'static'
|
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):
|
class Settings(BaseSettings):
|
||||||
|
debug: bool = False
|
||||||
session_key: str = secrets.token_hex(32)
|
session_key: str = secrets.token_hex(32)
|
||||||
csrf_key: str = secrets.token_hex(32)
|
csrf_key: str = secrets.token_hex(32)
|
||||||
|
|
||||||
|
|
||||||
settings = Settings()
|
settings = Settings()
|
||||||
|
|
||||||
|
|
||||||
|
# Jinja templates handler
|
||||||
templates = Jinja2Templates(
|
templates = Jinja2Templates(
|
||||||
directory=templates_dir,
|
directory=templates_dir,
|
||||||
)
|
)
|
||||||
|
|
12
app/main.py
12
app/main.py
|
@ -7,7 +7,7 @@ from starlette.middleware.sessions import SessionMiddleware
|
||||||
from starlette_wtf import CSRFProtectMiddleware
|
from starlette_wtf import CSRFProtectMiddleware
|
||||||
|
|
||||||
from . import common
|
from . import common
|
||||||
from .sql import db
|
from . import sql
|
||||||
|
|
||||||
from .paths import Paths
|
from .paths import Paths
|
||||||
# Add your paths below
|
# 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()
|
app = FastAPI()
|
||||||
|
|
||||||
|
# Mount static files server
|
||||||
app.mount(
|
app.mount(
|
||||||
'/static',
|
'/static',
|
||||||
StaticFiles(directory=common.static_dir),
|
StaticFiles(directory=common.static_dir),
|
||||||
name='static',
|
name='static',
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Add paths
|
||||||
for p in paths:
|
for p in paths:
|
||||||
p(app).add_paths()
|
p(app).add_paths()
|
||||||
|
|
||||||
|
# Add WTForms CSRF protection middlewares
|
||||||
app.add_middleware(
|
app.add_middleware(
|
||||||
SessionMiddleware,
|
SessionMiddleware,
|
||||||
secret_key=common.settings.session_key,
|
secret_key=common.settings.session_key,
|
||||||
|
|
|
@ -20,6 +20,7 @@ class ErrorsPaths(Paths):
|
||||||
|
|
||||||
def add_paths(self) -> None:
|
def add_paths(self) -> None:
|
||||||
|
|
||||||
|
# For each HTTP code specified above
|
||||||
for code in codes:
|
for code in codes:
|
||||||
self.add_handler(code)
|
self.add_handler(code)
|
||||||
|
|
||||||
|
@ -31,14 +32,19 @@ class ErrorsPaths(Paths):
|
||||||
code (int): HTTP error code
|
code (int): HTTP error code
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
# Jinja template file name
|
||||||
|
# e.g. 404.html for 404 code
|
||||||
file = Path(common.templates_dir) / f'{code}.html'
|
file = Path(common.templates_dir) / f'{code}.html'
|
||||||
|
|
||||||
|
# Exit from the function
|
||||||
|
# if the template does not exist
|
||||||
if not file.exists():
|
if not file.exists():
|
||||||
return
|
return
|
||||||
|
|
||||||
@self.app.exception_handler(code)
|
@self.app.exception_handler(code)
|
||||||
async def handler(req: Request, exc: HTTPException) -> Response:
|
async def handler(req: Request, exc: HTTPException) -> Response:
|
||||||
|
|
||||||
|
# Respond with the template
|
||||||
return respond.with_tmpl(
|
return respond.with_tmpl(
|
||||||
f'{code}.html',
|
f'{code}.html',
|
||||||
code=code,
|
code=code,
|
||||||
|
|
|
@ -9,7 +9,7 @@ from starlette_wtf import csrf_protect
|
||||||
|
|
||||||
from . import Paths
|
from . import Paths
|
||||||
from .. import respond
|
from .. import respond
|
||||||
from ..sql import db
|
from .. import sql
|
||||||
from ..sql import crud
|
from ..sql import crud
|
||||||
from ..sql import schemas
|
from ..sql import schemas
|
||||||
from ..forms import get_form
|
from ..forms import get_form
|
||||||
|
@ -26,7 +26,7 @@ class TablePaths(Paths):
|
||||||
def list_users(
|
def list_users(
|
||||||
req: Request,
|
req: Request,
|
||||||
page: int = 0,
|
page: int = 0,
|
||||||
db: Session = Depends(db.get_db)) -> Response:
|
db: Session = Depends(sql.get_db)) -> Response:
|
||||||
|
|
||||||
return respond.with_tmpl(
|
return respond.with_tmpl(
|
||||||
'table.html',
|
'table.html',
|
||||||
|
@ -43,7 +43,7 @@ class TablePaths(Paths):
|
||||||
@csrf_protect
|
@csrf_protect
|
||||||
async def add_form(
|
async def add_form(
|
||||||
req: Request,
|
req: Request,
|
||||||
db_s: Session = Depends(db.get_db)) -> Response:
|
db_s: Session = Depends(sql.get_db)) -> Response:
|
||||||
|
|
||||||
form = await get_form(AddUserForm, req)
|
form = await get_form(AddUserForm, req)
|
||||||
|
|
||||||
|
|
|
@ -16,12 +16,12 @@ from .common import templates
|
||||||
def with_redirect(
|
def with_redirect(
|
||||||
url: str = '/',
|
url: str = '/',
|
||||||
code: int = 302,
|
code: int = 302,
|
||||||
*args, **kwargs) -> RedirectResponse:
|
**kwargs) -> RedirectResponse:
|
||||||
"""Return a redirect to the page specified in `url`.
|
"""Return a redirect to the page specified in `url`.
|
||||||
By default, code is 302 so method is changed to GET.
|
By default, code is 302 so method is changed to GET.
|
||||||
To leave the same HTTP method, use 307 status code
|
To leave the same HTTP method, use 307 status code
|
||||||
or call `with_redirect_307` function.
|
or call `with_redirect_307` function.
|
||||||
`args` and `kwargs` are passed directly
|
`kwargs` are passed directly
|
||||||
to the Response contructor
|
to the Response contructor
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
|
@ -35,16 +35,16 @@ def with_redirect(
|
||||||
return RedirectResponse(
|
return RedirectResponse(
|
||||||
url=url,
|
url=url,
|
||||||
status_code=code,
|
status_code=code,
|
||||||
*args, **kwargs,
|
**kwargs,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def with_text(
|
def with_text(
|
||||||
content: str,
|
content: str,
|
||||||
code: int = 200,
|
code: int = 200,
|
||||||
*args, **kwargs) -> PlainTextResponse:
|
**kwargs) -> PlainTextResponse:
|
||||||
"""Return a plain text to the user.
|
"""Return a plain text to the user.
|
||||||
`args` and `kwargs` are passed directly
|
`kwargs` are passed directly
|
||||||
to the Response contructor
|
to the Response contructor
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
|
@ -58,7 +58,7 @@ def with_text(
|
||||||
return PlainTextResponse(
|
return PlainTextResponse(
|
||||||
content=content,
|
content=content,
|
||||||
status_code=code,
|
status_code=code,
|
||||||
*args, **kwargs,
|
**kwargs,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@ -117,10 +117,10 @@ def with_file(
|
||||||
path: os.PathLike,
|
path: os.PathLike,
|
||||||
mime: Optional[str] = None,
|
mime: Optional[str] = None,
|
||||||
code: int = 200,
|
code: int = 200,
|
||||||
*args, **kwargs) -> FileResponse:
|
**kwargs) -> FileResponse:
|
||||||
"""Send the file specified in `path`
|
"""Send the file specified in `path`
|
||||||
automatically guessing its mimetype if `mime` is None.
|
automatically guessing its mimetype if `mime` is None.
|
||||||
`args` and `kwargs` are passed directly
|
`kwargs` are passed directly
|
||||||
to the Response contructor
|
to the Response contructor
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
|
@ -139,7 +139,7 @@ def with_file(
|
||||||
mimetypes.guess_type(path)[0]
|
mimetypes.guess_type(path)[0]
|
||||||
),
|
),
|
||||||
status_code=code,
|
status_code=code,
|
||||||
*args, **kwargs,
|
**kwargs,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -3,12 +3,14 @@ from typing import AsyncGenerator
|
||||||
from pydantic import BaseSettings
|
from pydantic import BaseSettings
|
||||||
|
|
||||||
from sqlalchemy import create_engine
|
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.orm import Session, sessionmaker
|
||||||
from sqlalchemy.ext.declarative import declarative_base
|
from sqlalchemy.ext.declarative import declarative_base
|
||||||
|
|
||||||
|
from sqlalchemy_utils import database_exists
|
||||||
|
from sqlalchemy_utils import create_database
|
||||||
|
|
||||||
|
|
||||||
|
# Database configuration
|
||||||
class SqlSettings(BaseSettings):
|
class SqlSettings(BaseSettings):
|
||||||
db_host: str = '${REPO_NAME_SNAKE}_db'
|
db_host: str = '${REPO_NAME_SNAKE}_db'
|
||||||
db_port: int = 3306
|
db_port: int = 3306
|
||||||
|
@ -16,26 +18,36 @@ class SqlSettings(BaseSettings):
|
||||||
db_password: str = ''
|
db_password: str = ''
|
||||||
db_database: str = '${REPO_NAME_SNAKE}'
|
db_database: str = '${REPO_NAME_SNAKE}'
|
||||||
|
|
||||||
|
|
||||||
sql_settings = SqlSettings()
|
sql_settings = SqlSettings()
|
||||||
|
|
||||||
|
# DB connection URL
|
||||||
|
# pylint: disable=consider-using-f-string
|
||||||
db_url = (
|
db_url = (
|
||||||
'mysql://{db_user}:{db_password}@'
|
'mysql://{db_user}:{db_password}@'
|
||||||
'{db_host}:{db_port}/{db_database}'
|
'{db_host}:{db_port}/{db_database}'
|
||||||
).format(**sql_settings.dict())
|
).format(**sql_settings.dict())
|
||||||
|
# pylint: enable=consider-using-f-string
|
||||||
|
|
||||||
|
|
||||||
|
# SQLAlchemy engine object
|
||||||
engine = create_engine(db_url)
|
engine = create_engine(db_url)
|
||||||
|
|
||||||
|
# Create DB if not exists
|
||||||
if not database_exists(db_url):
|
if not database_exists(db_url):
|
||||||
create_database(db_url)
|
create_database(db_url)
|
||||||
|
|
||||||
|
# SQLAlchemy Session object
|
||||||
SessionLocal = sessionmaker(
|
SessionLocal = sessionmaker(
|
||||||
autoflush=False,
|
autoflush=False,
|
||||||
bind=engine,
|
bind=engine,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# SQLAlchemy Base object
|
||||||
Base = declarative_base()
|
Base = declarative_base()
|
||||||
|
|
||||||
|
|
||||||
|
# FastAPI dependency
|
||||||
async def get_db() -> AsyncGenerator[Session, None]:
|
async def get_db() -> AsyncGenerator[Session, None]:
|
||||||
"""FastAPI dependency
|
"""FastAPI dependency
|
||||||
returning database Session object.
|
returning database Session object.
|
|
@ -6,6 +6,7 @@ from . import models
|
||||||
from . import schemas
|
from . import schemas
|
||||||
|
|
||||||
|
|
||||||
|
# SELECT * from users LIMIT 1
|
||||||
def get_user(
|
def get_user(
|
||||||
db: Session,
|
db: Session,
|
||||||
user_id: int) -> Optional[models.User]:
|
user_id: int) -> Optional[models.User]:
|
||||||
|
@ -16,6 +17,7 @@ def get_user(
|
||||||
.first()
|
.first()
|
||||||
|
|
||||||
|
|
||||||
|
# SELECT * from users
|
||||||
def get_users(
|
def get_users(
|
||||||
db: Session,
|
db: Session,
|
||||||
skip: int = 0,
|
skip: int = 0,
|
||||||
|
@ -28,6 +30,7 @@ def get_users(
|
||||||
.all()
|
.all()
|
||||||
|
|
||||||
|
|
||||||
|
# INSERT INTO users
|
||||||
def create_user(
|
def create_user(
|
||||||
db: Session,
|
db: Session,
|
||||||
user: schemas.UserCreate) -> models.User:
|
user: schemas.UserCreate) -> models.User:
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
from sqlalchemy import Column, String, Integer
|
from sqlalchemy import Column, String, Integer
|
||||||
|
|
||||||
from .db import Base
|
from . import Base
|
||||||
|
|
||||||
|
|
||||||
class User(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):
|
class UserCreate(BaseModel):
|
||||||
email: str
|
email: str
|
||||||
name: str
|
name: str
|
||||||
age: int
|
age: int
|
||||||
|
|
||||||
|
|
||||||
|
# Pydantic class for
|
||||||
|
# SELECT responses with User model(-s)
|
||||||
class User(UserCreate):
|
class User(UserCreate):
|
||||||
id: int
|
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]
|
[MAIN]
|
||||||
analyse-fallback-blocks=no
|
analyse-fallback-blocks=no
|
||||||
|
clear-cache-post-run=no
|
||||||
extension-pkg-allow-list=
|
extension-pkg-allow-list=
|
||||||
extension-pkg-whitelist=
|
extension-pkg-whitelist=
|
||||||
fail-on=
|
fail-on=
|
||||||
|
@ -17,113 +18,6 @@ recursive=no
|
||||||
suggestion-mode=yes
|
suggestion-mode=yes
|
||||||
unsafe-load-any-extension=no
|
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]
|
[BASIC]
|
||||||
argument-naming-style=snake_case
|
argument-naming-style=snake_case
|
||||||
attr-naming-style=snake_case
|
attr-naming-style=snake_case
|
||||||
|
@ -158,6 +52,105 @@ no-docstring-rgx=^_
|
||||||
property-classes=abc.abstractproperty
|
property-classes=abc.abstractproperty
|
||||||
variable-naming-style=snake_case
|
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]
|
[SPELLING]
|
||||||
max-spelling-suggestions=4
|
max-spelling-suggestions=4
|
||||||
spelling-dict=
|
spelling-dict=
|
||||||
|
@ -166,6 +159,10 @@ spelling-ignore-words=
|
||||||
spelling-private-dict-file=
|
spelling-private-dict-file=
|
||||||
spelling-store-unknown-words=no
|
spelling-store-unknown-words=no
|
||||||
|
|
||||||
|
[STRING]
|
||||||
|
check-quote-consistency=no
|
||||||
|
check-str-concat-over-line-jumps=no
|
||||||
|
|
||||||
[TYPECHECK]
|
[TYPECHECK]
|
||||||
contextmanager-decorators=contextlib.contextmanager
|
contextmanager-decorators=contextlib.contextmanager
|
||||||
generated-members=
|
generated-members=
|
||||||
|
@ -182,6 +179,13 @@ missing-member-max-choices=1
|
||||||
mixin-class-rgx=.*[Mm]ixin
|
mixin-class-rgx=.*[Mm]ixin
|
||||||
signature-mutators=
|
signature-mutators=
|
||||||
|
|
||||||
[REFACTORING]
|
[VARIABLES]
|
||||||
max-nested-blocks=5
|
additional-builtins=
|
||||||
never-returning-functions=sys.exit,argparse.parse_error
|
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