mirror of
https://github.com/flibusta-apps/telegram_files_server.git
synced 2025-12-06 12:35:39 +01:00
Add linters config
This commit is contained in:
35
.github/workflows/linters.yaml
vendored
Normal file
35
.github/workflows/linters.yaml
vendored
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
name: Linters
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
pull_request:
|
||||||
|
types: [opened, synchronize, reopened]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
Run-Pre-Commit:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
with:
|
||||||
|
fetch-depth: 32
|
||||||
|
|
||||||
|
- uses: actions/setup-python@v2
|
||||||
|
with:
|
||||||
|
python-version: 3.9
|
||||||
|
|
||||||
|
- name: Install pre-commit
|
||||||
|
run: pip3 install pre-commit
|
||||||
|
|
||||||
|
- name: Pre-commit (Push)
|
||||||
|
env:
|
||||||
|
SETUPTOOLS_USE_DISTUTILS: stdlib
|
||||||
|
if: ${{ github.event_name == 'push' }}
|
||||||
|
run: pre-commit run --source ${{ github.event.before }} --origin ${{ github.event.after }} --show-diff-on-failure
|
||||||
|
|
||||||
|
- name: Pre-commit (Pull-Request)
|
||||||
|
env:
|
||||||
|
SETUPTOOLS_USE_DISTUTILS: stdlib
|
||||||
|
if: ${{ github.event_name == 'pull_request' }}
|
||||||
|
run: pre-commit run --source ${{ github.event.pull_request.base.sha }} --origin ${{ github.event.pull_request.head.sha }} --show-diff-on-failure
|
||||||
20
.pre-commit-config.yaml
Normal file
20
.pre-commit-config.yaml
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
exclude: 'docs|node_modules|migrations|.git|.tox'
|
||||||
|
|
||||||
|
repos:
|
||||||
|
- repo: https://github.com/ambv/black
|
||||||
|
rev: 21.12b0
|
||||||
|
hooks:
|
||||||
|
- id: black
|
||||||
|
language_version: python3.9
|
||||||
|
- repo: https://github.com/pycqa/isort
|
||||||
|
rev: 5.10.1
|
||||||
|
hooks:
|
||||||
|
- id: isort
|
||||||
|
- repo: https://github.com/csachs/pyproject-flake8
|
||||||
|
rev: v0.0.1a2.post1
|
||||||
|
hooks:
|
||||||
|
- id: pyproject-flake8
|
||||||
|
additional_dependencies: [
|
||||||
|
'-e', 'git+https://github.com/pycqa/pyflakes@1911c20#egg=pyflakes',
|
||||||
|
'-e', 'git+https://github.com/pycqa/pycodestyle@d219c68#egg=pycodestyle',
|
||||||
|
]
|
||||||
@@ -1 +1 @@
|
|||||||
__version__ = '0.1.0'
|
__version__ = "0.1.0"
|
||||||
|
|||||||
@@ -1,20 +1,22 @@
|
|||||||
from logging.config import fileConfig
|
from logging.config import fileConfig
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
|
||||||
from alembic import context
|
from alembic import context
|
||||||
import sys, os
|
|
||||||
|
|
||||||
from sqlalchemy.engine import create_engine
|
from sqlalchemy.engine import create_engine
|
||||||
|
|
||||||
from core.db import DATABASE_URL
|
from core.db import DATABASE_URL
|
||||||
|
|
||||||
|
|
||||||
myPath = os.path.dirname(os.path.abspath(__file__))
|
myPath = os.path.dirname(os.path.abspath(__file__))
|
||||||
sys.path.insert(0, myPath + '/../../')
|
sys.path.insert(0, myPath + "/../../")
|
||||||
|
|
||||||
config = context.config
|
config = context.config
|
||||||
|
|
||||||
|
|
||||||
from app.models import BaseMeta
|
from app.models import BaseMeta
|
||||||
|
|
||||||
|
|
||||||
target_metadata = BaseMeta.metadata
|
target_metadata = BaseMeta.metadata
|
||||||
|
|
||||||
|
|
||||||
@@ -52,9 +54,7 @@ def run_migrations_online():
|
|||||||
connectable = create_engine(DATABASE_URL)
|
connectable = create_engine(DATABASE_URL)
|
||||||
|
|
||||||
with connectable.connect() as connection:
|
with connectable.connect() as connection:
|
||||||
context.configure(
|
context.configure(connection=connection, target_metadata=target_metadata)
|
||||||
connection=connection, target_metadata=target_metadata
|
|
||||||
)
|
|
||||||
|
|
||||||
with context.begin_transaction():
|
with context.begin_transaction():
|
||||||
context.run_migrations()
|
context.run_migrations()
|
||||||
|
|||||||
@@ -9,24 +9,31 @@ from alembic import op
|
|||||||
import sqlalchemy as sa
|
import sqlalchemy as sa
|
||||||
from sqlalchemy.dialects import postgresql
|
from sqlalchemy.dialects import postgresql
|
||||||
|
|
||||||
|
|
||||||
# revision identifiers, used by Alembic.
|
# revision identifiers, used by Alembic.
|
||||||
revision = '3bbf7cb4eaa2'
|
revision = "3bbf7cb4eaa2"
|
||||||
down_revision = '5a32159504fd'
|
down_revision = "5a32159504fd"
|
||||||
branch_labels = None
|
branch_labels = None
|
||||||
depends_on = None
|
depends_on = None
|
||||||
|
|
||||||
|
|
||||||
def upgrade():
|
def upgrade():
|
||||||
# ### commands auto generated by Alembic - please adjust! ###
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
op.alter_column('uploaded_files', 'upload_time',
|
op.alter_column(
|
||||||
|
"uploaded_files",
|
||||||
|
"upload_time",
|
||||||
existing_type=postgresql.TIMESTAMP(timezone=True),
|
existing_type=postgresql.TIMESTAMP(timezone=True),
|
||||||
nullable=True)
|
nullable=True,
|
||||||
|
)
|
||||||
# ### end Alembic commands ###
|
# ### end Alembic commands ###
|
||||||
|
|
||||||
|
|
||||||
def downgrade():
|
def downgrade():
|
||||||
# ### commands auto generated by Alembic - please adjust! ###
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
op.alter_column('uploaded_files', 'upload_time',
|
op.alter_column(
|
||||||
|
"uploaded_files",
|
||||||
|
"upload_time",
|
||||||
existing_type=postgresql.TIMESTAMP(timezone=True),
|
existing_type=postgresql.TIMESTAMP(timezone=True),
|
||||||
nullable=False)
|
nullable=False,
|
||||||
|
)
|
||||||
# ### end Alembic commands ###
|
# ### end Alembic commands ###
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import sqlalchemy as sa
|
|||||||
|
|
||||||
|
|
||||||
# revision identifiers, used by Alembic.
|
# revision identifiers, used by Alembic.
|
||||||
revision = '5a32159504fd'
|
revision = "5a32159504fd"
|
||||||
down_revision = None
|
down_revision = None
|
||||||
branch_labels = None
|
branch_labels = None
|
||||||
depends_on = None
|
depends_on = None
|
||||||
@@ -18,17 +18,18 @@ depends_on = None
|
|||||||
|
|
||||||
def upgrade():
|
def upgrade():
|
||||||
# ### commands auto generated by Alembic - please adjust! ###
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
op.create_table('uploaded_files',
|
op.create_table(
|
||||||
sa.Column('id', sa.BigInteger(), nullable=True),
|
"uploaded_files",
|
||||||
sa.Column('backend', sa.String(length=16), nullable=False),
|
sa.Column("id", sa.BigInteger(), nullable=True),
|
||||||
sa.Column('data', sa.JSON(), nullable=False),
|
sa.Column("backend", sa.String(length=16), nullable=False),
|
||||||
sa.Column('upload_time', sa.DateTime(timezone=True), nullable=False),
|
sa.Column("data", sa.JSON(), nullable=False),
|
||||||
sa.PrimaryKeyConstraint('id')
|
sa.Column("upload_time", sa.DateTime(timezone=True), nullable=False),
|
||||||
|
sa.PrimaryKeyConstraint("id"),
|
||||||
)
|
)
|
||||||
# ### end Alembic commands ###
|
# ### end Alembic commands ###
|
||||||
|
|
||||||
|
|
||||||
def downgrade():
|
def downgrade():
|
||||||
# ### commands auto generated by Alembic - please adjust! ###
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
op.drop_table('uploaded_files')
|
op.drop_table("uploaded_files")
|
||||||
# ### end Alembic commands ###
|
# ### end Alembic commands ###
|
||||||
|
|||||||
@@ -6,4 +6,6 @@ from core.config import env_config
|
|||||||
|
|
||||||
async def check_token(api_key: str = Security(default_security)):
|
async def check_token(api_key: str = Security(default_security)):
|
||||||
if api_key != env_config.API_KEY:
|
if api_key != env_config.API_KEY:
|
||||||
raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="Wrong api key!")
|
raise HTTPException(
|
||||||
|
status_code=status.HTTP_403_FORBIDDEN, detail="Wrong api key!"
|
||||||
|
)
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
from enum import Enum
|
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
from enum import Enum
|
||||||
|
|
||||||
import ormar
|
import ormar
|
||||||
|
|
||||||
@@ -12,8 +12,8 @@ class BaseMeta(ormar.ModelMeta):
|
|||||||
|
|
||||||
|
|
||||||
class UploadBackends(str, Enum):
|
class UploadBackends(str, Enum):
|
||||||
aiogram = 'aiogram'
|
aiogram = "aiogram"
|
||||||
telethon = 'telethon'
|
telethon = "telethon"
|
||||||
|
|
||||||
|
|
||||||
class UploadedFile(ormar.Model):
|
class UploadedFile(ormar.Model):
|
||||||
|
|||||||
@@ -1,11 +1,12 @@
|
|||||||
from typing import Optional
|
|
||||||
from io import BytesIO
|
from io import BytesIO
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
from fastapi import UploadFile
|
from fastapi import UploadFile
|
||||||
|
|
||||||
from telegram_files_storage import AiogramFilesStorage, TelethonFilesStorage
|
from telegram_files_storage import AiogramFilesStorage, TelethonFilesStorage
|
||||||
|
|
||||||
from core.config import env_config
|
|
||||||
from app.models import UploadedFile, UploadBackends
|
from app.models import UploadedFile, UploadBackends
|
||||||
|
from core.config import env_config
|
||||||
|
|
||||||
|
|
||||||
class FileUploader:
|
class FileUploader:
|
||||||
@@ -67,7 +68,9 @@ class FileUploader:
|
|||||||
|
|
||||||
storage = self.get_telethon_storage()
|
storage = self.get_telethon_storage()
|
||||||
|
|
||||||
self.upload_data = await storage.upload(bytes_io, caption=self.caption) # type: ignore
|
self.upload_data = await storage.upload(
|
||||||
|
bytes_io, caption=self.caption
|
||||||
|
) # type: ignore
|
||||||
self.upload_backend = UploadBackends.telethon
|
self.upload_backend = UploadBackends.telethon
|
||||||
|
|
||||||
return True
|
return True
|
||||||
@@ -82,12 +85,18 @@ class FileUploader:
|
|||||||
async def prepare(cls):
|
async def prepare(cls):
|
||||||
if env_config.BOT_TOKENS:
|
if env_config.BOT_TOKENS:
|
||||||
cls.AIOGRAM_STORAGES: list[AiogramFilesStorage] = [
|
cls.AIOGRAM_STORAGES: list[AiogramFilesStorage] = [
|
||||||
AiogramFilesStorage(env_config.TELEGRAM_CHAT_ID, token) for token in env_config.BOT_TOKENS
|
AiogramFilesStorage(env_config.TELEGRAM_CHAT_ID, token)
|
||||||
|
for token in env_config.BOT_TOKENS
|
||||||
]
|
]
|
||||||
|
|
||||||
if env_config.TELETHON_APP_CONFIG and env_config.TELETHON_SESSIONS:
|
if env_config.TELETHON_APP_CONFIG and env_config.TELETHON_SESSIONS:
|
||||||
cls.TELETHON_STORAGES: list[TelethonFilesStorage] = [
|
cls.TELETHON_STORAGES: list[TelethonFilesStorage] = [
|
||||||
TelethonFilesStorage(env_config.TELEGRAM_CHAT_ID, env_config.TELETHON_APP_CONFIG.APP_ID, env_config.TELETHON_APP_CONFIG.API_HASH, session)
|
TelethonFilesStorage(
|
||||||
|
env_config.TELEGRAM_CHAT_ID,
|
||||||
|
env_config.TELETHON_APP_CONFIG.APP_ID,
|
||||||
|
env_config.TELETHON_APP_CONFIG.API_HASH,
|
||||||
|
session,
|
||||||
|
)
|
||||||
for session in env_config.TELETHON_SESSIONS
|
for session in env_config.TELETHON_SESSIONS
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -99,7 +108,9 @@ class FileUploader:
|
|||||||
if not cls.AIOGRAM_STORAGES:
|
if not cls.AIOGRAM_STORAGES:
|
||||||
raise ValueError("Aiogram storage not exist!")
|
raise ValueError("Aiogram storage not exist!")
|
||||||
|
|
||||||
cls._aiogram_storage_index = (cls._aiogram_storage_index + 1) % len(cls.AIOGRAM_STORAGES)
|
cls._aiogram_storage_index = (cls._aiogram_storage_index + 1) % len(
|
||||||
|
cls.AIOGRAM_STORAGES
|
||||||
|
)
|
||||||
|
|
||||||
return cls.AIOGRAM_STORAGES[cls._aiogram_storage_index]
|
return cls.AIOGRAM_STORAGES[cls._aiogram_storage_index]
|
||||||
|
|
||||||
@@ -108,12 +119,16 @@ class FileUploader:
|
|||||||
if not cls.TELETHON_STORAGES:
|
if not cls.TELETHON_STORAGES:
|
||||||
raise ValueError("Telethon storage not exists!")
|
raise ValueError("Telethon storage not exists!")
|
||||||
|
|
||||||
cls._telethon_storage_index = (cls._telethon_storage_index + 1) % len(cls.TELETHON_STORAGES)
|
cls._telethon_storage_index = (cls._telethon_storage_index + 1) % len(
|
||||||
|
cls.TELETHON_STORAGES
|
||||||
|
)
|
||||||
|
|
||||||
return cls.TELETHON_STORAGES[cls._telethon_storage_index]
|
return cls.TELETHON_STORAGES[cls._telethon_storage_index]
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def upload(cls, file: UploadFile, caption: Optional[str] = None) -> Optional[UploadedFile]:
|
async def upload(
|
||||||
|
cls, file: UploadFile, caption: Optional[str] = None
|
||||||
|
) -> Optional[UploadedFile]:
|
||||||
uploader = cls(file, caption)
|
uploader = cls(file, caption)
|
||||||
upload_result = await uploader._upload()
|
upload_result = await uploader._upload()
|
||||||
|
|
||||||
|
|||||||
@@ -1,19 +1,17 @@
|
|||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
from fastapi import File, UploadFile, Depends, Form
|
from fastapi import File, UploadFile, Depends, Form, APIRouter, HTTPException
|
||||||
from starlette import status
|
|
||||||
from fastapi import APIRouter, HTTPException
|
|
||||||
|
|
||||||
|
from starlette import status
|
||||||
|
|
||||||
|
from app.depends import check_token
|
||||||
from app.models import UploadedFile as UploadedFileDB
|
from app.models import UploadedFile as UploadedFileDB
|
||||||
from app.serializers import UploadedFile, CreateUploadedFile
|
from app.serializers import UploadedFile, CreateUploadedFile
|
||||||
from app.services.file_uploader import FileUploader
|
from app.services.file_uploader import FileUploader
|
||||||
from app.depends import check_token
|
|
||||||
|
|
||||||
|
|
||||||
router = APIRouter(
|
router = APIRouter(
|
||||||
prefix="/api/v1/files",
|
prefix="/api/v1/files", dependencies=[Depends(check_token)], tags=["files"]
|
||||||
dependencies=[Depends(check_token)],
|
|
||||||
tags=["files"]
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@@ -22,9 +20,13 @@ async def get_files():
|
|||||||
return await UploadedFileDB.objects.all()
|
return await UploadedFileDB.objects.all()
|
||||||
|
|
||||||
|
|
||||||
@router.get("/{file_id}", response_model=UploadedFile, responses={
|
@router.get(
|
||||||
|
"/{file_id}",
|
||||||
|
response_model=UploadedFile,
|
||||||
|
responses={
|
||||||
404: {},
|
404: {},
|
||||||
})
|
},
|
||||||
|
)
|
||||||
async def get_file(file_id: int):
|
async def get_file(file_id: int):
|
||||||
uploaded_file = await UploadedFileDB.objects.get_or_none(id=file_id)
|
uploaded_file = await UploadedFileDB.objects.get_or_none(id=file_id)
|
||||||
|
|
||||||
@@ -36,9 +38,7 @@ async def get_file(file_id: int):
|
|||||||
|
|
||||||
@router.post("/", response_model=UploadedFile)
|
@router.post("/", response_model=UploadedFile)
|
||||||
async def create_file(data: CreateUploadedFile):
|
async def create_file(data: CreateUploadedFile):
|
||||||
return await UploadedFileDB.objects.create(
|
return await UploadedFileDB.objects.create(**data.dict())
|
||||||
**data.dict()
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
@router.post("/upload/", response_model=UploadedFile)
|
@router.post("/upload/", response_model=UploadedFile)
|
||||||
@@ -46,9 +46,7 @@ async def upload_file(file: UploadFile = File({}), caption: Optional[str] = Form
|
|||||||
return await FileUploader.upload(file, caption=caption)
|
return await FileUploader.upload(file, caption=caption)
|
||||||
|
|
||||||
|
|
||||||
@router.delete("/{file_id}", response_model=UploadedFile, responses={
|
@router.delete("/{file_id}", response_model=UploadedFile, responses={400: {}})
|
||||||
400: {}
|
|
||||||
})
|
|
||||||
async def delete_file(file_id: int):
|
async def delete_file(file_id: int):
|
||||||
uploaded_file = await UploadedFileDB.objects.get_or_none(id=file_id)
|
uploaded_file = await UploadedFileDB.objects.get_or_none(id=file_id)
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
from fastapi import FastAPI
|
from fastapi import FastAPI
|
||||||
|
|
||||||
from core.db import database
|
|
||||||
from app.on_start import on_start
|
from app.on_start import on_start
|
||||||
from app.views import router
|
from app.views import router
|
||||||
|
from core.db import database
|
||||||
|
|
||||||
|
|
||||||
def start_app() -> FastAPI:
|
def start_app() -> FastAPI:
|
||||||
@@ -12,7 +12,7 @@ def start_app() -> FastAPI:
|
|||||||
|
|
||||||
app.include_router(router)
|
app.include_router(router)
|
||||||
|
|
||||||
@app.on_event('startup')
|
@app.on_event("startup")
|
||||||
async def startup() -> None:
|
async def startup() -> None:
|
||||||
database_ = app.state.database
|
database_ = app.state.database
|
||||||
if not database_.is_connected:
|
if not database_.is_connected:
|
||||||
@@ -20,7 +20,7 @@ def start_app() -> FastAPI:
|
|||||||
|
|
||||||
await on_start()
|
await on_start()
|
||||||
|
|
||||||
@app.on_event('shutdown')
|
@app.on_event("shutdown")
|
||||||
async def shutdown() -> None:
|
async def shutdown() -> None:
|
||||||
database_ = app.state.database
|
database_ = app.state.database
|
||||||
if database_.is_connected:
|
if database_.is_connected:
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
from fastapi.security import APIKeyHeader
|
from fastapi.security import APIKeyHeader
|
||||||
from fastapi.security.utils import get_authorization_scheme_param
|
|
||||||
|
|
||||||
|
|
||||||
default_security = APIKeyHeader(name="Authorization")
|
default_security = APIKeyHeader(name="Authorization")
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
from pydantic import BaseModel, BaseSettings
|
from pydantic import BaseModel, BaseSettings
|
||||||
|
|
||||||
|
|
||||||
BotToken = str
|
BotToken = str
|
||||||
TelethonSessionName= str
|
TelethonSessionName = str
|
||||||
|
|
||||||
|
|
||||||
class TelethonConfig(BaseModel):
|
class TelethonConfig(BaseModel):
|
||||||
APP_ID: int
|
APP_ID: int
|
||||||
@@ -27,8 +29,8 @@ class EnvConfig(BaseSettings):
|
|||||||
TELETHON_SESSIONS: Optional[list[TelethonSessionName]]
|
TELETHON_SESSIONS: Optional[list[TelethonSessionName]]
|
||||||
|
|
||||||
class Config:
|
class Config:
|
||||||
env_file = '.env'
|
env_file = ".env"
|
||||||
env_file_encoding = 'utf-8'
|
env_file_encoding = "utf-8"
|
||||||
|
|
||||||
|
|
||||||
env_config = EnvConfig()
|
env_config = EnvConfig()
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
from urllib.parse import quote
|
from urllib.parse import quote
|
||||||
from databases import Database
|
|
||||||
|
|
||||||
|
from databases import Database
|
||||||
from sqlalchemy import MetaData
|
from sqlalchemy import MetaData
|
||||||
|
|
||||||
from core.config import env_config
|
from core.config import env_config
|
||||||
|
|||||||
@@ -24,3 +24,43 @@ mypy = "^0.910"
|
|||||||
[build-system]
|
[build-system]
|
||||||
requires = ["poetry-core>=1.0.0"]
|
requires = ["poetry-core>=1.0.0"]
|
||||||
build-backend = "poetry.core.masonry.api"
|
build-backend = "poetry.core.masonry.api"
|
||||||
|
|
||||||
|
[tool.black]
|
||||||
|
include = '\.pyi?$'
|
||||||
|
exclude = '''
|
||||||
|
/(
|
||||||
|
\.git
|
||||||
|
| \.vscode
|
||||||
|
| \venv
|
||||||
|
| alembic
|
||||||
|
)/
|
||||||
|
'''
|
||||||
|
|
||||||
|
[tool.flake8]
|
||||||
|
ignore = [
|
||||||
|
# Whitespace before ':' ( https://www.flake8rules.com/rules/E203.html )
|
||||||
|
"E203"
|
||||||
|
]
|
||||||
|
max-line-length=88
|
||||||
|
max-complexity = 15
|
||||||
|
select = "B,C,E,F,W,T4,B9"
|
||||||
|
exclude = [
|
||||||
|
# No need to traverse our git directory
|
||||||
|
".git",
|
||||||
|
# There's no value in checking cache directories
|
||||||
|
"__pycache__",
|
||||||
|
# The conf file is mostly autogenerated, ignore it
|
||||||
|
"fastapi_file_server/app/alembic/*",
|
||||||
|
# The old directory contains Flake8 2.0
|
||||||
|
]
|
||||||
|
|
||||||
|
[tool.isort]
|
||||||
|
profile = "black"
|
||||||
|
only_sections = true
|
||||||
|
force_sort_within_sections = true
|
||||||
|
lines_after_imports = 2
|
||||||
|
lexicographical = true
|
||||||
|
sections = ["FUTURE", "STDLIB", "BASEFRAMEWORK", "FRAMEWORKEXT", "THIRDPARTY", "FIRSTPARTY", "LOCALFOLDER"]
|
||||||
|
known_baseframework = ["fastapi",]
|
||||||
|
known_frameworkext = ["starlette",]
|
||||||
|
src_paths = ["fastapi_file_server"]
|
||||||
|
|||||||
@@ -2,4 +2,4 @@ from fastapi_file_server import __version__
|
|||||||
|
|
||||||
|
|
||||||
def test_version():
|
def test_version():
|
||||||
assert __version__ == '0.1.0'
|
assert __version__ == "0.1.0"
|
||||||
|
|||||||
Reference in New Issue
Block a user