Repository navigation
Add support for local mypy, pylint, black checks #14
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Radhika Gupta (rads-1996)
merged 7 commits into
microsoft:main
from
rads-1996:add-tox-checks
Apr 6, 2026
Merged
Changes from all commits
Commits
Show all changes
7 commits
Select commit
Hold shift + click to select a range
20df4cd
Add support for local mypy, pylint, black checks
rads-1996 bcf5ba4
Update eng/tox/tox.ini
rads-1996 53c8799
Update eng/tox/tox.ini
rads-1996 f3c5540
Address feedback
rads-1996 2de4986
Disable import errors in samples
rads-1996 104ca86
Modify black setup
rads-1996 180b4c4
Merge branch 'main' into add-tox-checks
rads-1996 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,2 @@ | ||
| pytest>=8.0 | ||
| black>=24.0 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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) | ||
|
|
||
| # 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) | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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} | ||
|
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} | ||
|
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} | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,19 @@ | ||
| import os | ||
|
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() | ||
| ), | ||
|
rads-1996 marked this conversation as resolved.
rads-1996 marked this conversation as resolved.
|
||
| ) | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.