chore: Switch to nox, read config from python file
This commit is contained in:
parent
ff30346bbd
commit
a389da81a4
|
@ -0,0 +1,11 @@
|
|||
[flake8]
|
||||
filename= marshpy tests
|
||||
ignore =
|
||||
# Line too long
|
||||
E501
|
||||
include = marshpy,test
|
||||
max-complexity = 10
|
||||
per-file-ignores =
|
||||
# Imported but unused
|
||||
__init__.py:F401
|
||||
|
|
@ -1,8 +1,10 @@
|
|||
**/__pycache__/**
|
||||
**/__pycache__
|
||||
*.egg-info
|
||||
.mypy_cache
|
||||
.nox
|
||||
.pytest_cache
|
||||
.ropeproject
|
||||
.venv
|
||||
build
|
||||
poetry.lock
|
||||
poetry.toml
|
||||
test_config.py
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
""" Core module for Frontools"""
|
||||
|
||||
from .config import Config, SiteConfig
|
|
@ -2,7 +2,6 @@
|
|||
from asyncio import run
|
||||
from functools import update_wrapper
|
||||
from pathlib import Path
|
||||
from sys import exit as sys_exit
|
||||
from typing import Any, Optional
|
||||
|
||||
from click import Context
|
||||
|
@ -29,14 +28,13 @@ def _async_command(function: Any) -> Any:
|
|||
type=PathArgument(exists=True, file_okay=True, dir_okay=False),
|
||||
default=None,
|
||||
metavar="FILE",
|
||||
help="Configuration file to use"
|
||||
help="Configuration file to use",
|
||||
)
|
||||
def main(ctx: Context, config_file: Optional[Path]) -> None:
|
||||
"""Utilities for EO frontend development.
|
||||
"""
|
||||
@_async_command
|
||||
async def main(ctx: Context, config_file: Optional[Path]) -> None:
|
||||
"""Utilities for EO frontend development."""
|
||||
|
||||
ctx.obj = load_config(config_file)
|
||||
pass
|
||||
ctx.obj = await load_config(config_file)
|
||||
|
||||
|
||||
@main.command(name="css-diff")
|
||||
|
|
|
@ -1,36 +1,74 @@
|
|||
"""Config loading"""
|
||||
from gettext import gettext as _
|
||||
from importlib.util import module_from_spec, spec_from_file_location
|
||||
from inspect import isawaitable
|
||||
from pathlib import Path
|
||||
from typing import Optional
|
||||
from typing import Iterable, Optional
|
||||
|
||||
from xdg import xdg_config_dirs
|
||||
|
||||
from marshpy import load, ANNOTATION_RESOLVER_CONFIG
|
||||
|
||||
class ConfigError(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class Site:
|
||||
class SiteConfig:
|
||||
urls: list[str]
|
||||
|
||||
def __init__(self, urls: Iterable[str]):
|
||||
self.urls = list(urls)
|
||||
|
||||
|
||||
class Config:
|
||||
sites: dict[str, Site] = {}
|
||||
sites: dict[str, SiteConfig] = {}
|
||||
|
||||
|
||||
def load_config(config_path: Optional[Path]) -> Config:
|
||||
async def load_config(config_path: Optional[Path]) -> Config:
|
||||
if config_path is None:
|
||||
config_path = _find_config()
|
||||
if config_path is None:
|
||||
return Config()
|
||||
|
||||
with open(config_path, 'r', encoding='utf-8') as config_file:
|
||||
return load(config_file, Config, config = [ANNOTATION_RESOLVER_CONFIG])
|
||||
module_spec = spec_from_file_location("frontools.local_config", config_path)
|
||||
assert module_spec is not None
|
||||
config_module = module_from_spec(module_spec)
|
||||
|
||||
assert module_spec is not None
|
||||
module_spec.loader.exec_module(config_module) # type: ignore
|
||||
|
||||
if not hasattr(config_module, "CONFIG"):
|
||||
raise ConfigError(
|
||||
_(f"Configuration file {config_path} should define a root variable CONFIG.")
|
||||
)
|
||||
|
||||
config_provider = getattr(config_module, "CONFIG")
|
||||
if callable(config_provider):
|
||||
config_value = config_provider()
|
||||
|
||||
if isawaitable(config_value):
|
||||
config = await config_value
|
||||
else:
|
||||
config = config_value
|
||||
else:
|
||||
config = config_provider
|
||||
|
||||
if not isinstance(config, Config):
|
||||
raise ConfigError(
|
||||
_(
|
||||
f"The configuratio exported by {config_path} is not an instance of frontools.Config."
|
||||
)
|
||||
)
|
||||
|
||||
return config
|
||||
|
||||
|
||||
def _find_config() -> Optional[Path]:
|
||||
local_config = Path('.frontools.yaml')
|
||||
local_config = Path(".frontools.py")
|
||||
if local_config.is_file():
|
||||
return local_config
|
||||
|
||||
for config_dir in xdg_config_dirs():
|
||||
config_path = config_dir / 'frontools/config.yaml'
|
||||
config_path = config_dir / "frontools/config.py"
|
||||
if config_path.is_file():
|
||||
return config_path
|
||||
|
||||
|
|
|
@ -0,0 +1,112 @@
|
|||
"""Nox configuration file"""
|
||||
from os import fsdecode
|
||||
from pathlib import Path
|
||||
|
||||
import nox
|
||||
from nox import Session
|
||||
|
||||
nox.options.sessions = ["checks"]
|
||||
|
||||
LINT_PATHS = ["frontools", "tests"]
|
||||
PYTEST_PACKAGES = ["pytest", "pytest-cov", "pytest-datadir"]
|
||||
DEV_DEPENDENCIES = PYTEST_PACKAGES + ["mypy", "pylint", "flake8", "isort", "poetry"]
|
||||
VENV_DIR = Path(".venv")
|
||||
|
||||
|
||||
@nox.session(python=["3.9", "3.10"], reuse_venv=True)
|
||||
def tests(session: Session):
|
||||
"""Run unit tests."""
|
||||
session.install("-e", ".", *PYTEST_PACKAGES)
|
||||
session.run("pytest")
|
||||
|
||||
|
||||
@nox.session(reuse_venv=True)
|
||||
def black(session: Session):
|
||||
"""Check black formatting."""
|
||||
session.install("black")
|
||||
session.run("black", "--check", *LINT_PATHS)
|
||||
|
||||
|
||||
@nox.session(reuse_venv=True)
|
||||
def flake8(session: Session):
|
||||
"""Run flake8"""
|
||||
session.install("flake8")
|
||||
session.run("flake8")
|
||||
|
||||
|
||||
@nox.session(reuse_venv=True)
|
||||
def isort(session: Session):
|
||||
"""Check imports sorting"""
|
||||
session.install("isort")
|
||||
session.run("isort", "--check", *LINT_PATHS)
|
||||
|
||||
|
||||
@nox.session(reuse_venv=True)
|
||||
def mypy(session: Session):
|
||||
"""Run Mypy"""
|
||||
session.install("mypy", "types-PyYAML")
|
||||
session.run("mypy", *LINT_PATHS)
|
||||
|
||||
|
||||
@nox.session(reuse_venv=True)
|
||||
def pylint(session: Session):
|
||||
"""Run pylint"""
|
||||
session.install("pylint", "-e", ".", *PYTEST_PACKAGES)
|
||||
session.run("pylint", "--rcfile=pyproject.toml", *LINT_PATHS)
|
||||
|
||||
|
||||
@nox.session(python=False)
|
||||
def lint(session: Session):
|
||||
"""Run all lint tasks"""
|
||||
session.notify("black")
|
||||
session.notify("flake8")
|
||||
session.notify("isort")
|
||||
session.notify("mypy")
|
||||
session.notify("pylint")
|
||||
|
||||
|
||||
@nox.session(python=False)
|
||||
def checks(session: Session):
|
||||
"""Run all checks"""
|
||||
session.notify("lint")
|
||||
session.notify("tests")
|
||||
|
||||
|
||||
@nox.session(python=False)
|
||||
def dev(session: Session) -> None:
|
||||
"""
|
||||
Sets up a python development environment for the project.
|
||||
"""
|
||||
|
||||
session.run(
|
||||
"python3",
|
||||
"-m",
|
||||
"virtualenv",
|
||||
"-p",
|
||||
"python3.10",
|
||||
fsdecode(VENV_DIR),
|
||||
silent=True,
|
||||
)
|
||||
python_path = Path.cwd() / VENV_DIR / "bin/python"
|
||||
python = fsdecode(python_path)
|
||||
session.run(
|
||||
python,
|
||||
"-m",
|
||||
"pip",
|
||||
"install",
|
||||
"-e",
|
||||
".",
|
||||
*DEV_DEPENDENCIES,
|
||||
external=True,
|
||||
silent=True
|
||||
)
|
||||
|
||||
|
||||
@nox.session(python="3.10")
|
||||
def publish(session: Session) -> None:
|
||||
"""
|
||||
Publish a package to pypi
|
||||
"""
|
||||
|
||||
session.install("poetry", "poetry-dynamic-versioning")
|
||||
session.run("poetry", "publish", "--build")
|
|
@ -1,40 +1,81 @@
|
|||
[build-system]
|
||||
requires = ['poetry-core>=1.0.0', 'poetry-dynamic-versioning']
|
||||
build-backend = 'poetry.core.masonry.api'
|
||||
|
||||
[tool.poetry]
|
||||
name = "frontools"
|
||||
version = "0.1.0"
|
||||
description = "Frontend Automation"
|
||||
authors = ["Corentin Séchet <csechet@entrouvert.com>"]
|
||||
license = "WTFPL"
|
||||
name = 'frontools'
|
||||
version = '0.0.0'
|
||||
description = 'Web QA tasks automation'
|
||||
authors = ['Corentin Séchet <csechet@entrouvert.com>']
|
||||
license = 'WTFPL'
|
||||
readme = 'README.md'
|
||||
repository = 'https://git.entrouvert.org/frontools'
|
||||
keywords = ['web', 'QA', 'Tests' ]
|
||||
classifiers = [
|
||||
"Development Status :: 3 - Alpha",
|
||||
"Intended Audience :: Developers",
|
||||
"Operating System :: OS Independent",
|
||||
"Programming Language :: Python",
|
||||
"Programming Language :: Python :: 3.9",
|
||||
"Programming Language :: Python :: 3.10",
|
||||
"Programming Language :: Python :: Implementation :: CPython",
|
||||
"Programming Language :: Python :: Implementation :: PyPy",
|
||||
"Topic :: Software Development :: Libraries :: Python Modules",
|
||||
]
|
||||
packages = [
|
||||
{ include = 'frontools/**/*' },
|
||||
]
|
||||
|
||||
[tool.poetry.dependencies]
|
||||
python = "^3.9"
|
||||
click = "^8.0.4"
|
||||
playwright = "^1.20.0"
|
||||
python= ">3.7,<4.0"
|
||||
bs4 = "^0.0.1"
|
||||
xdg = "^5.1.1"
|
||||
beautifulsoup4 = "^4.10.0"
|
||||
PyYAML = "^6.0"
|
||||
playwright = "^1.20.1"
|
||||
|
||||
[tool.poetry.dev-dependencies]
|
||||
pylint = "^2.12.2"
|
||||
pytest = "^7.1.1"
|
||||
mypy = "^0.941"
|
||||
isort = "^5.10.1"
|
||||
black = "^22.1.0"
|
||||
mypy = "^0.942"
|
||||
pylint = "^2.13.2"
|
||||
|
||||
[tool.poetry.scripts]
|
||||
frontools = 'frontools.cli:main'
|
||||
[tool.poetry-dynamic-versioning]
|
||||
enable = true
|
||||
|
||||
[build-system]
|
||||
requires = ["poetry-core>=1.0.0"]
|
||||
build-backend = "poetry.core.masonry.api"
|
||||
[tool.pytest.ini_options]
|
||||
junit_family = "legacy"
|
||||
addopts = "--cov=frontools --cov-report html"
|
||||
testpaths = "tests"
|
||||
|
||||
[tool.pycodestyle]
|
||||
ignore = ["E501"]
|
||||
|
||||
[tool.mypy]
|
||||
[[tool.mypy.overrides]]
|
||||
module = [
|
||||
'pytest',
|
||||
'nox',
|
||||
'xdg',
|
||||
'bs4',
|
||||
'playwright.async_api'
|
||||
]
|
||||
ignore_missing_imports = true
|
||||
strict = true
|
||||
|
||||
[tool.isort]
|
||||
profile = "black"
|
||||
|
||||
[tool.pylint.messages_control]
|
||||
disable = [
|
||||
"line-too-long", # Already checked by pep8
|
||||
"unsubscriptable-object", # https://github.com/PyCQA/pylint/issues/3882
|
||||
"invalid-name",
|
||||
"too-few-public-methods",
|
||||
"line-too-long", # Already checked by black
|
||||
"too-many-arguments",
|
||||
]
|
||||
|
||||
[tool.pylint.similaritie]
|
||||
ignore-imports=true
|
||||
ignore-signatures=true
|
||||
|
||||
[tool.coverage.report]
|
||||
exclude_lines = [
|
||||
"pragma: no cover",
|
||||
"raise AssertionError",
|
||||
"raise NotImplementedError",
|
||||
"if 0:",
|
||||
"if __name__ == .__main__.:"
|
||||
]
|
||||
|
|
|
@ -1,5 +0,0 @@
|
|||
sites:
|
||||
auch:
|
||||
urls:
|
||||
- http://demarches.auch.fr
|
||||
|
Loading…
Reference in New Issue