Skip to content

Commit 4d4fcbf

Browse files
authored
refactor: Improved project code quality (#53)
* test: Switched to pytest * docs: Updated documentation * ci: Updated CI jobs * style: Updated import order * style: Updated import order * refactor: Refactored setup * feat: Added isort, pydocstyle and contribution utils * style: Fixed lint * chore: Fixed documentation reqs
1 parent 358edb6 commit 4d4fcbf

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

46 files changed

+1510
-550
lines changed

.flake8

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
[flake8]
22
max-line-length = 120
3-
ignore = F401, E402, E265, F403, W503, W504, F821, W605
3+
ignore = E402, E265, F403, W503, W504, E731
44
exclude = .github, .git, venv*, docs, build
5+
per-file-ignores = **/__init__.py:F401

.github/ISSUE_TEMPLATE/bug_report.md

-45
This file was deleted.

.github/ISSUE_TEMPLATE/bug_report.yml

+64
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
name: 🐛 Bug report
2+
description: Create a report to help us improve the library
3+
labels: 'type: bug'
4+
assignees: frgfm
5+
6+
body:
7+
- type: markdown
8+
attributes:
9+
value: >
10+
#### Before reporting a bug, please check that the issue hasn't already been addressed in [the existing and past issues](https://github.com/frgfm/torch-cam/issues?q=is%3Aissue).
11+
- type: textarea
12+
attributes:
13+
label: Bug description
14+
description: |
15+
A clear and concise description of what the bug is.
16+
17+
Please explain the result you observed and the behavior you were expecting.
18+
placeholder: |
19+
A clear and concise description of what the bug is.
20+
validations:
21+
required: true
22+
23+
- type: textarea
24+
attributes:
25+
label: Code snippet to reproduce the bug
26+
description: |
27+
Sample code to reproduce the problem.
28+
29+
Please wrap your code snippet with ```` ```triple quotes blocks``` ```` for readability.
30+
placeholder: |
31+
```python
32+
Sample code to reproduce the problem
33+
```
34+
validations:
35+
required: true
36+
- type: textarea
37+
attributes:
38+
label: Error traceback
39+
description: |
40+
The error message you received running the code snippet, with the full traceback.
41+
42+
Please wrap your error message with ```` ```triple quotes blocks``` ```` for readability.
43+
placeholder: |
44+
```
45+
The error message you got, with the full traceback.
46+
```
47+
validations:
48+
required: true
49+
- type: textarea
50+
attributes:
51+
label: Environment
52+
description: |
53+
Please run the following command and paste the output below.
54+
```sh
55+
wget https://raw.githubusercontent.com/frgfm/torch-scan/master/scripts/collect_env.py
56+
# For security purposes, please check the contents of collect_env.py before running it.
57+
python collect_env.py
58+
```
59+
validations:
60+
required: true
61+
- type: markdown
62+
attributes:
63+
value: >
64+
Thanks for helping us improve the library!

.github/ISSUE_TEMPLATE/config.yml

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
blank_issues_enabled: true
2+
contact_links:
3+
- name: Usage questions
4+
url: https://github.com/frgfm/torch-scan/discussions
5+
about: Ask questions and discuss with other TorchCAM community members

.github/ISSUE_TEMPLATE/feature_request.md

-27
This file was deleted.
+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
name: 🚀 Feature request
2+
description: Submit a proposal/request for a new feature
3+
labels: 'type: enhancement'
4+
assignees: frgfm
5+
6+
body:
7+
- type: textarea
8+
attributes:
9+
label: 🚀 Feature
10+
description: >
11+
A clear and concise description of the feature proposal
12+
validations:
13+
required: true
14+
- type: textarea
15+
attributes:
16+
label: Motivation & pitch
17+
description: >
18+
Please outline the motivation for the proposal. Is your feature request related to a specific problem? e.g., *"I'm working on X and would like Y to be possible"*. If this is related to another GitHub issue, please link here too.
19+
validations:
20+
required: true
21+
- type: textarea
22+
attributes:
23+
label: Alternatives
24+
description: >
25+
A description of any alternative solutions or features you've considered, if any.
26+
- type: textarea
27+
attributes:
28+
label: Additional context
29+
description: >
30+
Add any other context or screenshots about the feature request.
31+
- type: markdown
32+
attributes:
33+
value: >
34+
Thanks for contributing 🎉

.github/PULL_REQUEST_TEMPLATE.md

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# What does this PR do?
2+
3+
<!--
4+
Well, hello there! Thank you for proposing modifications to the project.
5+
6+
Make sure to have both a short descriptive title & explain your modifications with the relevant context. Make sure to include reference to Github issues it is related to. For the sake of keeping the library light, if you modified existing dependencies or added new ones, please state it clearly in your description.
7+
8+
-->
9+
10+
<!-- Remove if not applicable -->
11+
12+
Closes # (issue)
13+
14+
15+
## Before submitting
16+
- [ ] Was this discussed/approved in a Github [issue](https://github.com/frgfm/torch-scan/issues?q=is%3Aissue) or a [discussion](https://github.com/frgfm/torch-scan/discussions)? Please add a link to it if that's the case.
17+
- [ ] You have read the [contribution guidelines](https://github.com/frgfm/torch-scan/blob/master/CONTRIBUTING.md#submitting-a-pull-request) and followed them in this PR.
18+
- [ ] Did you make sure to update the documentation with your changes? Here are the
19+
[documentation guidelines](https://github.com/frgm/torch-scan/tree/master/docs).
20+
- [ ] Did you write any new necessary tests?

.github/release.yml

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
changelog:
2+
exclude:
3+
labels:
4+
- ignore-for-release
5+
categories:
6+
- title: Breaking Changes 🛠
7+
labels:
8+
- "type: breaking change"
9+
# NEW FEATURES
10+
- title: New Features 🚀
11+
labels:
12+
- "type: new feature"
13+
# BUG FIXES
14+
- title: Bug Fixes 🐛
15+
labels:
16+
- "type: bug"
17+
# IMPROVEMENTS
18+
- title: Improvements
19+
labels:
20+
- "type: enhancement"
21+
# MISC
22+
- title: Miscellaneous
23+
labels:
24+
- "type: misc"

.github/validate_deps.py

+64
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
from pathlib import Path
2+
3+
import requirements
4+
from requirements.requirement import Requirement
5+
6+
# Deps that won't have a specific requirements.txt
7+
IGNORE = ["flake8", "isort", "mypy", "pydocstyle"]
8+
# All req files to check
9+
REQ_FILES = ["requirements.txt", "tests/requirements.txt", "docs/requirements.txt"]
10+
11+
12+
def main():
13+
14+
# Collect the deps from all requirements.txt
15+
folder = Path(__file__).parent.parent.absolute()
16+
req_deps = {}
17+
for file in REQ_FILES:
18+
with open(folder.joinpath(file), 'r') as f:
19+
_deps = [(req.name, req.specs) for req in requirements.parse(f)]
20+
21+
for _dep in _deps:
22+
lib, specs = _dep
23+
assert req_deps.get(lib, specs) == specs, f"conflicting deps for {lib}"
24+
req_deps[lib] = specs
25+
26+
# Collect the one from setup.py
27+
setup_deps = {}
28+
with open(folder.joinpath("setup.py"), 'r') as f:
29+
setup = f.readlines()
30+
lines = setup[setup.index("_deps = [\n") + 1:]
31+
lines = [_dep.strip() for _dep in lines[:lines.index("]\n")]]
32+
lines = [_dep.split('"')[1] for _dep in lines if _dep.startswith('"')]
33+
_reqs = [Requirement.parse(_line) for _line in lines]
34+
_deps = [(req.name, req.specs) for req in _reqs]
35+
for _dep in _deps:
36+
lib, specs = _dep
37+
assert setup_deps.get(lib) is None, f"conflicting deps for {lib}"
38+
setup_deps[lib] = specs
39+
40+
# Remove ignores
41+
for k in IGNORE:
42+
if isinstance(req_deps.get(k), list):
43+
del req_deps[k]
44+
if isinstance(setup_deps.get(k), list):
45+
del setup_deps[k]
46+
47+
# Compare them
48+
assert len(req_deps) == len(setup_deps)
49+
mismatches = []
50+
for k, v in setup_deps.items():
51+
assert isinstance(req_deps.get(k), list)
52+
if req_deps[k] != v:
53+
mismatches.append((k, v, req_deps[k]))
54+
55+
if len(mismatches) > 0:
56+
mismatch_str = "version specifiers mismatches:\n"
57+
mismatch_str += '\n'.join(
58+
f"- {lib}: {setup} (from setup.py) | {reqs} (from requirements)"
59+
for lib, setup, reqs in mismatches
60+
)
61+
raise AssertionError(mismatch_str)
62+
63+
if __name__ == "__main__":
64+
main()

.github/validate_headers.py

+64
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
from datetime import datetime
2+
from pathlib import Path
3+
4+
shebang = ["#!usr/bin/python\n"]
5+
blank_line = "\n"
6+
7+
# Possible years
8+
starting_year = 2020
9+
current_year = datetime.now().year
10+
11+
year_options = [f"{current_year}"] + [f"{year}-{current_year}" for year in range(starting_year, current_year)]
12+
copyright_notices = [
13+
[f"# Copyright (C) {year_str}, François-Guillaume Fernandez.\n"]
14+
for year_str in year_options
15+
]
16+
license_notice = [
17+
"# This program is licensed under the Apache License version 2.\n",
18+
"# See LICENSE or go to <https://www.apache.org/licenses/LICENSE-2.0.txt> for full license details.\n"
19+
]
20+
21+
# Define all header options
22+
HEADERS = [
23+
shebang + [blank_line] + copyright_notice + [blank_line] + license_notice
24+
for copyright_notice in copyright_notices
25+
] + [
26+
copyright_notice + [blank_line] + license_notice
27+
for copyright_notice in copyright_notices
28+
]
29+
30+
31+
IGNORED_FILES = ["version.py", "__init__.py"]
32+
FOLDERS = ["torchscan", "scripts"]
33+
34+
35+
def main():
36+
37+
invalid_files = []
38+
39+
# For every python file in the repository
40+
for folder in FOLDERS:
41+
for source_path in Path(__file__).parent.parent.joinpath(folder).rglob('**/*.py'):
42+
if source_path.name not in IGNORED_FILES:
43+
# Parse header
44+
header_length = max(len(option) for option in HEADERS)
45+
current_header = []
46+
with open(source_path) as f:
47+
for idx, line in enumerate(f):
48+
current_header.append(line)
49+
if idx == header_length - 1:
50+
break
51+
# Validate it
52+
if not any(
53+
"".join(current_header[:min(len(option), len(current_header))]) == "".join(option)
54+
for option in HEADERS
55+
):
56+
invalid_files.append(source_path)
57+
58+
if len(invalid_files) > 0:
59+
invalid_str = "\n- " + "\n- ".join(map(str, invalid_files))
60+
raise AssertionError(f"Invalid header in the following files:{invalid_str}")
61+
62+
63+
if __name__ == "__main__":
64+
main()

0 commit comments

Comments
 (0)