Skip to content

Commit

Permalink
Add style checker and formatter (#3299)
Browse files Browse the repository at this point in the history
  • Loading branch information
ofek authored Mar 15, 2019
1 parent a5d04b8 commit 87278a2
Show file tree
Hide file tree
Showing 10 changed files with 185 additions and 25 deletions.
7 changes: 7 additions & 0 deletions .flake8
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# TODO: port this to pyproject.toml when supported: https://gitlab.com/pycqa/flake8/merge_requests/245

[flake8]
select = B,C,E,F,W,B001,B003,B006,B007,B301,B305,B306,B902
ignore = E203,E722,W503
exclude = .eggs,.tox,build,compat.py,__init__.py,datadog_checks/dev/tooling/templates/*,datadog_checks/*/vendor/*
max-line-length = 120
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
# (C) Datadog, Inc. 2018
# All rights reserved
# Licensed under a 3-clause BSD style license (see LICENSE)
from __future__ import absolute_import

import json
import os
from base64 import urlsafe_b64encode
Expand Down
104 changes: 104 additions & 0 deletions datadog_checks_dev/datadog_checks/dev/plugin/tox.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
# (C) Datadog, Inc. 2019
# All rights reserved
# Licensed under a 3-clause BSD style license (see LICENSE)
from __future__ import absolute_import

import tox
import tox.config

STYLE_CHECK_ENV_NAME = 'style'
STYLE_FORMATTER_ENV_NAME = 'format_style'
STYLE_FLAG = 'dd_check_style'


@tox.hookimpl
def tox_configure(config):
"""
For more info, see: https://tox.readthedocs.io/en/latest/plugins.html
For an example, see: https://github.com/tox-dev/tox-travis
"""
sections = config._cfg.sections

# Cache these
make_envconfig = None
reader = None

# Default to false so:
# 1. we don't affect other projects using tox
# 2. check migrations can happen gradually
if str(sections.get('testenv', {}).get(STYLE_FLAG, 'false')).lower() == 'true':
# Disable flake8 since we already include that
config.envlist[:] = [env for env in config.envlist if not env.endswith('flake8')]

make_envconfig = get_make_envconfig(make_envconfig)
reader = get_reader(reader, config)

add_style_checker(config, sections, make_envconfig, reader)
add_style_formatter(config, sections, make_envconfig, reader)


def add_style_checker(config, sections, make_envconfig, reader):
# testenv:style
section = '{}{}'.format(tox.config.testenvprefix, STYLE_CHECK_ENV_NAME)
sections[section] = {
# These tools only support Python 3+
'basepython': 'python3',
'skip_install': 'true',
'deps': 'flake8\nflake8-bugbear\nblack\nisort[pyproject]>=4.3.15',
'commands': 'flake8 --config=../.flake8 .\nblack --check --diff .\nisort --check-only --diff --recursive .',
}

# Always add the environment configurations
config.envconfigs[STYLE_CHECK_ENV_NAME] = make_envconfig(
config, STYLE_CHECK_ENV_NAME, section, reader._subs, config
)

# Intentionally add to envlist when seeing what is available
if any('--listenvs' in arg for arg in config.args):
config.envlist.append(STYLE_CHECK_ENV_NAME)


def add_style_formatter(config, sections, make_envconfig, reader):
# testenv:format_style
section = '{}{}'.format(tox.config.testenvprefix, STYLE_FORMATTER_ENV_NAME)
sections[section] = {
# These tools only support Python 3+
'basepython': 'python3',
'skip_install': 'true',
'deps': 'black\nisort[pyproject]>=4.3.15',
# Run formatter AFTER sorting imports
'commands': 'isort --recursive .\nblack .',
}

# Always add the environment configurations
config.envconfigs[STYLE_FORMATTER_ENV_NAME] = make_envconfig(
config, STYLE_FORMATTER_ENV_NAME, section, reader._subs, config
)

# Intentionally add to envlist when seeing what is available
if any('--listenvs' in arg for arg in config.args):
config.envlist.append(STYLE_FORMATTER_ENV_NAME)


def get_make_envconfig(make_envconfig):
if make_envconfig is None:
make_envconfig = tox.config.ParseIni.make_envconfig

# Make this a non-bound method for Python 2 compatibility
make_envconfig = getattr(make_envconfig, '__func__', make_envconfig)

return make_envconfig


def get_reader(reader, config):
if reader is None:
# This is just boilerplate necessary to create a valid reader
reader = tox.config.SectionReader('tox', config._cfg)
reader.addsubstitutions(toxinidir=config.toxinidir, homedir=config.homedir)
reader.addsubstitutions(toxworkdir=config.toxworkdir)
config.distdir = reader.getpath('distdir', '{toxworkdir}/dist')
reader.addsubstitutions(distdir=config.distdir)
config.distshare = reader.getpath('distshare', '{homedir}/.tox/distshare')
reader.addsubstitutions(distshare=config.distshare)

return reader
18 changes: 13 additions & 5 deletions datadog_checks_dev/datadog_checks/dev/tooling/commands/test.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

import click

from .console import CONTEXT_SETTINGS, abort, echo_info, echo_success, echo_waiting
from .console import CONTEXT_SETTINGS, abort, echo_info, echo_success, echo_waiting, echo_warning
from ..constants import get_root
from ..testing import construct_pytest_options, fix_coverage_report, get_tox_envs, pytest_coverage_sources
from ...subprocess import run_command
Expand All @@ -24,6 +24,7 @@ def display_envs(check_envs):
short_help='Run tests'
)
@click.argument('checks', nargs=-1)
@click.option('--format-style', '-fs', is_flag=True, help='Run only the code style formatter')
@click.option('--style', '-s', is_flag=True, help='Run only style checks')
@click.option('--bench', '-b', is_flag=True, help='Run only benchmarks')
@click.option('--cov', '-c', 'coverage', is_flag=True, help='Measure code coverage')
Expand All @@ -38,6 +39,7 @@ def display_envs(check_envs):
@click.option('--cov-keep', is_flag=True, help='Keep coverage reports')
def test(
checks,
format_style,
style,
bench,
coverage,
Expand Down Expand Up @@ -98,11 +100,11 @@ def test(
'PYTEST_ADDOPTS': pytest_options,
}

check_envs = get_tox_envs(checks, style=style, benchmark=bench, changed_only=changed)
check_envs = get_tox_envs(checks, style=style, format_style=format_style, benchmark=bench, changed_only=changed)
tests_ran = False

for check, envs in check_envs:
# Many check don't have benchmark envs, etc.
# Many checks don't have benchmark envs, etc.
if not envs:
continue

Expand All @@ -121,7 +123,9 @@ def test(
echo_info('pytest options: `{}`'.format(test_env_vars['PYTEST_ADDOPTS']))

with chdir(os.path.join(root, check), env_vars=test_env_vars):
if style:
if format_style:
test_type_display = 'the code formatter'
elif style:
test_type_display = 'only style checks'
elif bench:
test_type_display = 'only benchmarks'
Expand Down Expand Up @@ -173,4 +177,8 @@ def test(
echo_success('\nPassed!')

if not tests_ran:
echo_info('Nothing to test!')
if format_style:
echo_warning('Code formatting is not enabled!')
echo_info('To enabled it, put `dd_check_style = true` under the `[testenv]` section of `tox.ini`.')
else:
echo_info('Nothing to test!')
Original file line number Diff line number Diff line change
@@ -1,7 +1,4 @@
{license_header}from .__about__ import __version__
from .{check_name} import {check_class}

__all__ = [
'__version__',
'{check_class}'
]
__all__ = ['__version__', '{check_class}']
Original file line number Diff line number Diff line change
Expand Up @@ -25,17 +25,13 @@
long_description=long_description,
long_description_content_type='text/markdown',
keywords='datadog agent {check_name} check',

# The project's main homepage.
url='https://github.com/DataDog/integrations-{repo_choice}',

# Author details
author='{author}',
author_email='{email_packages}',

# License
license='BSD-3-Clause',

# See https://pypi.org/classifiers
classifiers=[
'Development Status :: 5 - Production/Stable',
Expand All @@ -47,13 +43,10 @@
'Programming Language :: Python :: 3.6',
'Programming Language :: Python :: 3.7',
],

# The package we're going to ship
packages=['datadog_checks.{check_name}'],

# Run-time dependencies
install_requires=[CHECKS_BASE_REQ],

# Extra files to ship with the wheel package
include_package_data=True,
)
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ envlist =
flake8

[testenv]
dd_check_style = true
usedevelop = true
platform = linux|darwin|win32
deps =
Expand Down
18 changes: 11 additions & 7 deletions datadog_checks_dev/datadog_checks/dev/tooling/testing.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,11 @@
from ..subprocess import run_command
from ..utils import chdir, path_join, read_file_binary, write_file_binary

STYLE_ENVS = {
'flake8',
}
STYLE_CHECK_ENVS = {'flake8', 'style'}
STYLE_ENVS = {'flake8', 'style', 'format_style'}


def get_tox_envs(checks, style=False, benchmark=False, every=False, changed_only=False, sort=False):
def get_tox_envs(checks, style=False, format_style=False, benchmark=False, every=False, changed_only=False, sort=False):
testable_checks = get_testable_checks()
# Run `get_changed_checks` at most once because git calls are costly
changed_checks = get_changed_checks() if not checks or changed_only else None
Expand All @@ -36,10 +35,15 @@ def get_tox_envs(checks, style=False, benchmark=False, every=False, changed_only
envs_selected = envs_selected.split(',') if envs_selected else []
envs_available = get_available_tox_envs(check, sort=sort)

if style:
if format_style:
envs_selected[:] = [
e for e in envs_available
if e in STYLE_ENVS
if 'format_style' in e
]
elif style:
envs_selected[:] = [
e for e in envs_available
if e in STYLE_CHECK_ENVS
]
elif benchmark:
envs_selected[:] = [
Expand All @@ -64,7 +68,7 @@ def get_tox_envs(checks, style=False, benchmark=False, every=False, changed_only
else:
envs_selected[:] = [
e for e in envs_available
if 'bench' not in e
if 'bench' not in e and 'format_style' not in e
]

yield check, envs_selected
Expand Down
5 changes: 3 additions & 2 deletions datadog_checks_dev/setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,14 +83,15 @@
'semver',
'setuptools>=38.6.0',
'toml>=0.9.4, <1.0.0',
'tox',
'tox>=3.7.0',
'twine>=1.11.0',
'wheel>=0.31.0',
],
},

entry_points={
'pytest11': ['datadog_checks = datadog_checks.dev.plugin.plugin'],
'pytest11': ['datadog_checks = datadog_checks.dev.plugin.pytest'],
'tox': ['datadog_checks = datadog_checks.dev.plugin.tox'],
'console_scripts': [
'ddev = datadog_checks.dev.tooling.cli:ddev',
],
Expand Down
43 changes: 43 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,3 +1,46 @@
# NOTE: You have to use single-quoted strings in TOML for regular expressions.
# It's the equivalent of r-strings in Python. Multiline strings are treated as
# verbose regular expressions by Black. Use [ ] to denote a significant space
# character.

[tool.black]
exclude = '''
# Directories
/(
\.eggs
| \.git
| \.hg
| \.mypy_cache
| \.tox
| \.venv
| _build
| buck-out
| build
| dist
# New integration templates
| datadog_checks/dev/tooling/templates
# Vendored third party libraries
| datadog_checks/[^/]+/vendor
)/
|
# Files
(
# TODO: remove when upstream addresses https://github.com/DataDog/integrations-core/blob/c71e6d7204192a8002109da92452003598df2d28/datadog_checks_dev/datadog_checks/dev/tooling/signing.py#L9-L14
datadog_checks/dev/tooling/signing\.py$
)
'''
include = '\.pyi?$'
line-length = 120
py36 = false
skip-string-normalization = true

[tool.isort]
default_section = 'THIRDPARTY'
force_grid_wrap = 0
include_trailing_comma = true
known_first_party = 'datadog_checks'
line_length = 120
multi_line_output = 3
skip_glob = 'datadog_checks/dev/tooling/signing.py,datadog_checks/dev/tooling/templates/*,datadog_checks/*/vendor/*'
use_parentheses = true

0 comments on commit 87278a2

Please sign in to comment.