diff --git a/.azure/testing-template.yml b/.azure/testing-template.yml index 515f8b8b..d8b15ac2 100644 --- a/.azure/testing-template.yml +++ b/.azure/testing-template.yml @@ -29,7 +29,7 @@ jobs: # map the output variable from A into this job configs: $[ dependencies.check_diff.outputs['files.diff'] ] config: "${{ config }}" - DEVICES: $( python -c 'name = "$(Agent.Name)" ; gpus = name.split("_")[-1] if "_" in name else "0,1"; print(gpus)' ) + DEVICES: $( python -c 'name = "$(Agent.Name)" ; gpus = name.split("_")[-1] if "_" in name else "0"; print(gpus)' ) condition: or(eq(variables['Build.SourceBranch'], 'refs/heads/main'), contains(variables['configs'], variables['config'])) # how long to run the job before automatically cancelling @@ -49,27 +49,23 @@ jobs: options: "--gpus=all --shm-size=8g -v /usr/bin/docker:/tmp/docker:ro" steps: - - bash: | - echo "##vso[task.setvariable variable=CONTAINER_ID]$(head -1 /proc/self/cgroup|cut -d/ -f3)" - echo "##vso[task.setvariable variable=CUDA_VISIBLE_DEVICES]$(DEVICES)" - displayName: 'Set environment variables' - - bash: | whoami && id lspci | egrep 'VGA|3D' whereis nvidia nvidia-smi - echo $CUDA_VISIBLE_DEVICES - echo $CONTAINER_ID python --version pip --version pip list python -c "import torch ; print(torch.cuda.get_arch_list())" + echo "##vso[task.setvariable variable=CUDA_VISIBLE_DEVICES]$(DEVICES)" displayName: 'Image info & NVIDIA' - script: | - /tmp/docker exec -t -u 0 $CONTAINER_ID \ - sh -c "apt-get update && DEBIAN_FRONTEND=noninteractive apt-get -o Dpkg::Options::="--force-confold" -y install sudo" + container_id=$(head -1 /proc/self/cgroup|cut -d/ -f3) + /tmp/docker exec -t -u 0 $container_id \ + sh -c "apt-get update && DEBIAN_FRONTEND=noninteractive apt-get -o Dpkg::Options::="--force-confold" -y install sudo" + echo "##vso[task.setvariable variable=CONTAINER_ID]$container_id" displayName: 'Install Sudo in container (thanks Microsoft!)' - bash: | @@ -82,6 +78,8 @@ jobs: displayName: 'Install dependencies' - bash: | + echo $CUDA_VISIBLE_DEVICES + echo $CONTAINER_ID python -c "import torch ; mgpu = torch.cuda.device_count() ; assert mgpu > 0, f'GPU: {mgpu}'" displayName: 'Sanity check' diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index 98d6f30f..feb03313 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -18,7 +18,10 @@ assignees: '' -### Environment +### Additional context + +
+ Environment - OS (e.g., Linux): - Python version: @@ -26,6 +29,6 @@ assignees: '' - How you installed PyTorch (`conda`, `pip`, source): - Any other relevant information: -### Additional context +
diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md index a8996eda..e65b9d31 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -14,10 +14,6 @@ assignees: '' -### Pitch - - - ### Alternatives diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 080c3603..fee7c9df 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -1,16 +1,20 @@ -## Before submitting +## What does this PR do? -- [ ] Was this discussed/approved via a GitHub issue? (no need for typos and docs improvements) -- [ ] Did you create/update your **configuration file**? -- [ ] Did you **set `runtimes` in config** for GitHub action integration? -- [ ] Did you **add your config to CI** in Azure pipeline (only projects with 100+ GitHub stars)? -- [ ] Are all integration **tests passing**? +Fixes # (add a link to the created issue in your repository if any) +OR link your project for clarity. -## What does this PR do? \[optional\] +
+ Before submitting -Fixes # (issue) \[add a link to the created issue in your repository if any\] -OR link your project for clarity. +- [ ] Was this discussed/agreed via a GitHub issue? (no need for typos and docs improvements) +- [ ] Did you create/update your **configuration file**? (in case you are adding new integration) +- Did you **set `runtimes` in config** for GitHub action integration? +- [ ] Are all integration **tests passing**? + +
-## Did you have fun? + diff --git a/.github/workflows/ci_compatible.yml b/.github/workflows/ci_compatible.yml index 725840b6..723efddf 100644 --- a/.github/workflows/ci_compatible.yml +++ b/.github/workflows/ci_compatible.yml @@ -28,7 +28,7 @@ jobs: matrix: ${{ steps.diff-files.outputs.runtimes }} steps: - uses: actions/checkout@v3 - - uses: actions/setup-python@v2 + - uses: actions/setup-python@v4 with: python-version: 3.8 @@ -114,8 +114,16 @@ jobs: watcher: runs-on: ubuntu-latest needs: pytester + if: always() steps: - run: echo "${{ needs.pytester.result }}" + - name: failing... + if: needs.pytester.result == 'failure' + run: exit 1 + - name: cancelled or skipped... + if: contains(fromJSON('["cancelled", "skipped"]'), needs.pytester.result) + timeout-minutes: 1 + run: sleep 90 messenger: diff --git a/.github/workflows/ci_test-acts.yml b/.github/workflows/ci_test-acts.yml index 66d59c03..71cd56b2 100644 --- a/.github/workflows/ci_test-acts.yml +++ b/.github/workflows/ci_test-acts.yml @@ -25,7 +25,7 @@ jobs: steps: - uses: actions/checkout@v3 - name: Set up Python ${{ matrix.python }} - uses: actions/setup-python@v2 + uses: actions/setup-python@v4 with: python-version: ${{ matrix.python }} diff --git a/.github/workflows/dockers.yml b/.github/workflows/dockers.yml index fd9801c9..2aac8664 100644 --- a/.github/workflows/dockers.yml +++ b/.github/workflows/dockers.yml @@ -32,7 +32,7 @@ jobs: - name: Build and Publish Docker Hub # publish master/release - uses: docker/build-push-action@v2 + uses: docker/build-push-action@v4 with: build-args: | PYTORCH_VERSION=${{ matrix.pytorch_version }} diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index c215b9bd..021a114f 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -27,22 +27,10 @@ repos: args: [--py38-plus] name: Upgrade code - - repo: https://github.com/PyCQA/docformatter - rev: v1.5.1 + - repo: https://github.com/omnilib/ufmt + rev: v2.0.1 hooks: - - id: docformatter - args: [--in-place, --wrap-summaries=120, --wrap-descriptions=120] - - - repo: https://github.com/PyCQA/isort - rev: 5.11.4 - hooks: - - id: isort - - - repo: https://github.com/psf/black - rev: 22.12.0 - hooks: - - id: black - name: Black code + - id: ufmt - repo: https://github.com/executablebooks/mdformat rev: 0.7.16 @@ -57,8 +45,11 @@ repos: rev: v1.4.0 hooks: - id: yesqa + additional_dependencies: + - pep8-naming - - repo: https://github.com/PyCQA/flake8 - rev: 6.0.0 + - repo: https://github.com/charliermarsh/ruff-pre-commit + rev: v0.0.254 hooks: - - id: flake8 + - id: ruff + args: ["--fix"] diff --git a/LICENSE b/LICENSE index e8b95b65..799ea72e 100644 --- a/LICENSE +++ b/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright 2021-2022 Lightning-AI team + Copyright 2021-2023 Lightning-AI team Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/README.md b/README.md index dfd798f9..cb12cd0d 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ **Automated Testing for Lightning EcoSystem Projects** -[![Lightning](https://img.shields.io/badge/-Lightning-792ee5?logo=pytorchlightning&logoColor=white)](https://pytorchlightning.ai) +[![Lightning](https://img.shields.io/badge/-Lightning-792ee5?logo=pytorchlightning&logoColor=white)](https://lightning.ai) [![CI internal](https://github.com/Lightning-AI/ecosystem-ci/actions/workflows/ci_test-acts.yml/badge.svg?branch=main&event=push)](https://github.com/Lightning-AI/ecosystem-ci/actions/workflows/ci_test-acts.yml) [![codecov](https://codecov.io/gh/Lightning-AI/ecosystem-ci/branch/main/graph/badge.svg?token=binMTx5wr4)](https://codecov.io/gh/Lightning-AI/ecosystem-ci) [![pre-commit.ci status](https://results.pre-commit.ci/badge/github/Lightning-AI/ecosystem-ci/main.svg)](https://results.pre-commit.ci/latest/github/Lightning-AI/ecosystem-ci/main) @@ -73,10 +73,10 @@ Here are pre-requisites for your project before adding to the Lightning EcoSyste ### Additional suggestions and engagement rules - To qualify for GPU machines we require your project to have 100+ GitHub stars (please note that this is for capacity reasons and may change in the future) -- (**Optional**) Join our [Slack](https://www.pytorchlightning.ai/community) channel `#alerts-ecosystem-ci` to be notified if your project is breaking +- (**Optional**) Join our [Slack](https://www.lightning.ai/community) channel `#alerts-ecosystem-ci` to be notified if your project is breaking - (**Kind request**) include Lightning badge in your readme: ```md - [![Lightning](https://img.shields.io/badge/-Lightning-792ee5?logo=pytorchlightning&logoColor=white)](https://pytorchlightning.ai) + [![Lightning](https://img.shields.io/badge/-Lightning-792ee5?logo=pytorchlightning&logoColor=white)](https://lightning.ai) ``` ## Configuring my project diff --git a/_actions/assistant.py b/_actions/assistant.py index 1dd5ccee..1b29ce67 100644 --- a/_actions/assistant.py +++ b/_actions/assistant.py @@ -47,7 +47,12 @@ class AssistantCLI: _MANDATORY_FIELDS = (_FIELD_TARGET_REPO, _FIELD_REQUIRE) _FOLDER_TESTS = "_integrations" _PATH_CONFIGS = os.path.join(_PATH_ROOT, "configs") - _STATUS_SIGN = dict(success=":white_check_mark:", failure=":x:", cancelled=":no_entry_sign:") + _STATUS_SIGN = { + "success": ":white_check_mark:", + "failure": ":x:", + "cancelled": ":no_entry_sign:", + "skipped": ":grey_question:", + } @staticmethod def folder_local_tests() -> str: @@ -69,8 +74,7 @@ def find_all_configs(configs_folder: str = _PATH_CONFIGS) -> List[str]: """Find all configs YAML|YML in given folder recursively.""" files = glob.glob(os.path.join(configs_folder, "**", "*.yaml"), recursive=True) files += glob.glob(os.path.join(configs_folder, "**", "*.yml"), recursive=True) - files = [cfg.replace("configs/", "") if cfg.startswith("configs/") else cfg for cfg in files] - return files + return [cfg.replace("configs/", "") if cfg.startswith("configs/") else cfg for cfg in files] @staticmethod def list_runtimes(pr: Optional[int] = None, auth_token: Optional[str] = None) -> str: @@ -141,8 +145,7 @@ def _https( @staticmethod def _extras(extras: Union[str, list, tuple] = "") -> str: """Create a list of eventual extras fro pip installation.""" - extras = ",".join(extras) if isinstance(extras, (tuple, list, set)) else extras - return extras + return ",".join(extras) if isinstance(extras, (tuple, list, set)) else extras @staticmethod def _get_flags(repo: dict, defaults: Sequence[str] = ("--quiet",)) -> List[str]: @@ -153,8 +156,10 @@ def _get_flags(repo: dict, defaults: Sequence[str] = ("--quiet",)) -> List[str]: @staticmethod def _install_pip(repo: Dict[str, str]) -> str: - """Create command for installing a project from source (if HTTPS is given) or from PyPI (if at least name is - given). + """Create command for installing a project from source or from PyPI. + + - source: if HTTPS is given + - PyPI: if at least name is iven Args: repo: it is package or repository with additional key fields @@ -188,8 +193,7 @@ def _install_pip(repo: Dict[str, str]) -> str: if "checkout" in repo: pkg += f"=={repo['checkout']}" flags = AssistantCLI._get_flags(repo, defaults=("--quiet", "--upgrade")) - cmd = " ".join(["pip install", pkg, " ".join(flags)]) - return cmd + return " ".join(["pip install", pkg, " ".join(flags)]) @staticmethod def _install_repo(repo: Dict[str, str], remove_dir: bool = True) -> List[str]: @@ -250,7 +254,7 @@ def before_commands( config = AssistantCLI._load_config(config_file) cmds = config.get(f"before_{stage}", []) if not as_append: - cmds = os.linesep.join(list(AssistantCLI._BASH_SCRIPT) + cmds) + return os.linesep.join(list(AssistantCLI._BASH_SCRIPT) + cmds) return cmds @staticmethod @@ -308,15 +312,13 @@ def prepare_env(config_file: str = "config.yaml", path_root: str = _PATH_ROOT) - @staticmethod def _pytest_dirs(dirs: Union[None, str, list, tuple] = "") -> str: - dirs = "." if not dirs else dirs - dirs = " ".join(dirs) if isinstance(dirs, (tuple, list, set)) else dirs - return dirs + dirs = dirs if dirs else "." + return " ".join(dirs) if isinstance(dirs, (tuple, list, set)) else dirs @staticmethod def _pytest_args(args: Union[None, str, list, tuple] = "") -> str: args = args or "" - args = " ".join(args) if isinstance(args, (tuple, list, set)) else args - return args + return " ".join(args) if isinstance(args, (tuple, list, set)) else args @staticmethod def specify_tests(config_file: str = "config.yaml") -> str: diff --git a/pyproject.toml b/pyproject.toml index a6c54e38..375c62cf 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,10 +1,88 @@ +[tool.black] +# https://github.com/psf/black +line-length = 120 +exclude = "(.eggs|.git|.hg|.mypy_cache|.venv|_build|buck-out|build|dist)" + + [tool.isort] profile = "black" line_length = 120 force_sort_within_sections = "False" order_by_type = "False" -[tool.black] -# https://github.com/psf/black + +[tool.pytest.ini_options] +norecursedirs = [ + ".git", + ".github", + "dist", + "build", + "docs", +] +addopts = [ + "--strict-markers", + "--doctest-modules", + # "--doctest-plus", + "--color=yes", + "--disable-pytest-warnings", +] +# ToDo +#filterwarnings = ["error::FutureWarning"] +xfail_strict = true +junit_duration_report = "call" + +[tool.coverage.report] +exclude_lines = [ + "pragma: no cover", + "pass", +] + + +[tool.ruff] line-length = 120 -exclude = "(.eggs|.git|.hg|.mypy_cache|.venv|_build|buck-out|build|dist)" +# Enable Pyflakes `E` and `F` codes by default. +select = [ + "E", "W", # see: https://pypi.org/project/pycodestyle + "F", # see: https://pypi.org/project/pyflakes + "D", # see: https://pypi.org/project/pydocstyle + "N", # see: https://pypi.org/project/pep8-naming +] +extend-select = [ + "C4", # see: https://pypi.org/project/flake8-comprehensions + "PT", # see: https://pypi.org/project/flake8-pytest-style + "RET", # see: https://pypi.org/project/flake8-return + "SIM", # see: https://pypi.org/project/flake8-simplify +] +#ignore = [ +# "E731", # Do not assign a lambda expression, use a def +#] +# Exclude a variety of commonly ignored directories. +exclude = [ + ".eggs", + ".git", + ".mypy_cache", + ".ruff_cache", + "__pypackages__", + "_build", + "build", + "dist", + "docs" +] +ignore-init-module-imports = true +unfixable = ["F401"] + +[tool.ruff.per-file-ignores] +"setup.py" = ["D100", "SIM115"] +"__about__.py" = ["D100"] +"__init__.py" = ["D100"] + +[tool.ruff.pydocstyle] +# Use Google-style docstrings. +convention = "google" + +#[tool.ruff.pycodestyle] +#ignore-overlong-task-comments = true + +[tool.ruff.mccabe] +# Unlike Flake8, default to a complexity level of 10. +max-complexity = 10 diff --git a/requirements.txt b/requirements.txt index 63e439f6..febdad4b 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,7 +1,7 @@ Cython # some projects need it for compiling fire>=0.4 PyYAML>=5.3 -coverage>=5.0 -pytest>=5.0 +coverage>=6.0 +pytest>=7.0 requests pandas>1.0 diff --git a/setup.cfg b/setup.cfg deleted file mode 100644 index 79326dd0..00000000 --- a/setup.cfg +++ /dev/null @@ -1,23 +0,0 @@ -[tool:pytest] -norecursedirs = - .git - dist - build -addopts = - --doctest-modules - --durations=25 - --color=yes - -[coverage:report] -exclude_lines = - pragma: no-cover - pass - -[flake8] -max-line-length = 120 -exclude = .tox,*.egg,build,temp -select = E,W,F -doctests = True -verbose = 2 -# https://pep8.readthedocs.io/en/latest/intro.html#error-codes -format = pylint