Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions dev_requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
pytest>=8.0
black>=24.0
93 changes: 93 additions & 0 deletions eng/tox/run_mypy.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
#!/usr/bin/env python

# -------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License.txt in the project root for
# license information.
# --------------------------------------------------------------------------

"""Run mypy against the target package."""

import argparse
import logging
import os
import sys
from subprocess import CalledProcessError, check_call

logging.getLogger().setLevel(logging.INFO)

PYTHON_VERSION = "3.10"

if __name__ == "__main__":
parser = argparse.ArgumentParser(description="Run mypy against target folder.")
parser.add_argument(
"-t",
"--target",
dest="target_package",
help="The target package directory on disk.",
required=True,
)
args = parser.parse_args()

package_dir = os.path.abspath(args.target_package)
src_dir = os.path.join(package_dir, "src")

commands = [
sys.executable,
"-m",
"mypy",
"--python-version",
PYTHON_VERSION,
"--show-error-codes",
"--ignore-missing-imports",
]

# Check source code
src_code = [*commands, src_dir]
src_code_error = None
try:
logging.info("Running mypy on src: %s", src_code)
check_call(src_code)
except CalledProcessError as e:
src_code_error = e

# Check samples if they exist
sample_code_error = None
samples_dir = os.path.join(package_dir, "samples")
if os.path.exists(samples_dir):
sample_code = [
*commands,
"--check-untyped-defs",
"--follow-imports=silent",
samples_dir,
]
try:
logging.info("Running mypy on samples: %s", sample_code)
check_call(sample_code)
except CalledProcessError as e:
sample_code_error = e

# Check tests if they exist
test_code_error = None
tests_dir = os.path.join(package_dir, "tests")
if os.path.exists(tests_dir):
test_code = [
*commands,
"--check-untyped-defs",
"--follow-imports=silent",
tests_dir,
]
try:
logging.info("Running mypy on tests: %s", test_code)
check_call(test_code)
except CalledProcessError as e:
test_code_error = e

if src_code_error or sample_code_error or test_code_error:
if src_code_error:
logging.error("mypy failed on src code: %s", src_code_error)
if sample_code_error:
logging.error("mypy failed on sample code: %s", sample_code_error)
if test_code_error:
logging.error("mypy failed on test code: %s", test_code_error)
sys.exit(1)
73 changes: 73 additions & 0 deletions eng/tox/run_pylint.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
#!/usr/bin/env python

# -------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License.txt in the project root for
# license information.
# --------------------------------------------------------------------------

"""Run pylint against the target package."""

import argparse
import logging
import os
import sys
from subprocess import CalledProcessError, check_call

logging.getLogger().setLevel(logging.INFO)

if __name__ == "__main__":
parser = argparse.ArgumentParser(description="Run pylint against target folder.")
parser.add_argument(
"-t",
"--target",
dest="target_package",
help="The target package directory on disk.",
required=True,
)
args = parser.parse_args()

package_dir = os.path.abspath(args.target_package)
src_dir = os.path.join(package_dir, "src")

# Use pyproject.toml pylint config (picked up automatically)
commands = [
sys.executable,
"-m",
"pylint",
"--output-format=parseable",
]

exit_code = 0

# Lint source code
try:
src_cmd = [*commands, src_dir]
logging.info("Running pylint on src: %s", src_cmd)
check_call(src_cmd)
except CalledProcessError as e:
logging.error("pylint failed on src code with exit code %s", e.returncode)
exit_code = max(exit_code, e.returncode)

# Lint tests if they exist
tests_dir = os.path.join(package_dir, "tests")
if os.path.exists(tests_dir):
try:
tests_cmd = [*commands, tests_dir]
logging.info("Running pylint on tests: %s", tests_cmd)
check_call(tests_cmd)
except CalledProcessError as e:
logging.error("pylint failed on tests with exit code %s", e.returncode)
exit_code = max(exit_code, e.returncode)
Comment thread
rads-1996 marked this conversation as resolved.

# Lint samples if they exist (disable import-error since samples have their own dependencies)
samples_dir = os.path.join(package_dir, "samples")
if os.path.exists(samples_dir):
try:
samples_cmd = [*commands, "--disable=import-error", samples_dir]
logging.info("Running pylint on samples: %s", samples_cmd)
check_call(samples_cmd)
except CalledProcessError as e:
logging.error("pylint failed on samples with exit code %s", e.returncode)
exit_code = max(exit_code, e.returncode)
sys.exit(exit_code)
61 changes: 61 additions & 0 deletions eng/tox/tox.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
[tox]
requires =
tox>=4.4.10
envlist = pylint,mypy,black,pytest

[testenv]
skip_install = true
skipsdist = true
usedevelop = false
passenv = *
setenv =
PIP_EXTRA_INDEX_URL=https://pypi.org/simple
deps =
-r {tox_root}/dev_requirements.txt
install_command = python -m pip install {opts} {packages}
Comment thread
rads-1996 marked this conversation as resolved.

[testenv:mypy]
description = Typecheck the package with mypy (version {[testenv:mypy]mypy_version})
mypy_version = 1.18.1
skip_install = true
skipsdist = true
usedevelop = true
deps =
{[testenv]deps}
mypy=={[testenv:mypy]mypy_version}
commands =
python -m pip install -e {tox_root}
python {repository_root}/eng/tox/run_mypy.py -t {tox_root}

[testenv:pylint]
description = Lint the package with pylint (version {[testenv:pylint]pylint_version})
pylint_version = 3.2.7
skip_install = true
skipsdist = true
usedevelop = false
deps =
{[testenv]deps}
pylint=={[testenv:pylint]pylint_version}
Comment thread
rads-1996 marked this conversation as resolved.
commands =
python -m pip install -e {tox_root}
python {repository_root}/eng/tox/run_pylint.py -t {tox_root}

[testenv:black]
description = Format code with black
skip_install = true
skipsdist = true
deps =
black>=24.0
commands =
python -m black {tox_root}/src {tox_root}/tests {tox_root}/samples

[testenv:pytest]
description = Run tests with pytest
skip_install = true
skipsdist = true
deps =
{[testenv]deps}
pytest>=8.0
commands =
python -m pip install -e {tox_root}
python -m pytest {tox_root}/tests {posargs}
19 changes: 19 additions & 0 deletions eng/tox/toxfile.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import os
Comment thread
rads-1996 marked this conversation as resolved.
from pathlib import Path

from tox import plugin
from tox.config.sets import CoreConfigSet
from tox.session.state import State


@plugin.impl
def tox_add_core_config(core_conf: CoreConfigSet, state: State):
core_conf.add_constant(
"repository_root",
"The root of this git repository",
next(
p
for p in Path(core_conf["config_file_path"]).resolve().parents
if (p / ".git").exists()
),
Comment thread
rads-1996 marked this conversation as resolved.
Comment thread
rads-1996 marked this conversation as resolved.
)
Loading