forked from scientific-python/cookie
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathgeneral.py
More file actions
144 lines (103 loc) · 3.7 KB
/
general.py
File metadata and controls
144 lines (103 loc) · 3.7 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
from __future__ import annotations
from typing import Any
from .._compat.importlib.resources.abc import Traversable
from . import mk_url
# PY: Python Project
## 0xx: File existence
class General:
family = "general"
class PY001(General):
"Has a pyproject.toml"
url = mk_url("packaging-simple")
@staticmethod
def check(package: Traversable) -> bool:
"""
All projects should have a `pyproject.toml` file to support a modern
build system and support wheel installs properly.
"""
return package.joinpath("pyproject.toml").is_file()
class PY002(General):
"Has a README.(md|rst) file"
url = mk_url("packaging-simple")
@staticmethod
def check(root: Traversable) -> bool:
"Projects must have a readme file"
return (
root.joinpath("README.md").is_file()
or root.joinpath("README.rst").is_file()
)
class PY003(General):
"Has a LICENSE* file"
url = mk_url("packaging-simple")
@staticmethod
def check(package: Traversable) -> bool:
"Projects must have a license"
spellings = ("LICENSE", "LICENCE", "COPYING")
return any(
p.name.startswith(spelling)
for p in package.iterdir()
for spelling in spellings
)
class PY004(General):
"Has docs folder"
url = mk_url("packaging-simple")
@staticmethod
def check(package: Traversable) -> bool:
"Projects must have documentation in a folder called doc or docs (disable if not applicable)"
return len([p for p in package.iterdir() if "doc" in p.name]) > 0
class PY004b(General):
"Documentation folder should be `docs` not `doc`"
requires = {"PY004"}
url = mk_url("packaging-simple")
@staticmethod
def check(package: Traversable) -> bool:
"Projects must have documentation in a folder called `docs` not `doc`"
return any(p.name == "docs" for p in package.iterdir())
class PY005(General):
"Has tests folder"
url = mk_url("packaging-simple")
@staticmethod
def check(package: Traversable) -> bool:
"Projects must have a folder called `*test*` or `src/*/*test*`"
# Out-of-source tests
if len([p for p in package.iterdir() if "test" in p.name]) > 0:
return True
# In-source tests
src = package.joinpath("src")
if src.is_dir():
for pkg in src.iterdir():
if len([p for p in pkg.iterdir() if "test" in p.name]) > 0:
return True
return False
class PY006(General):
"Has pre-commit config"
url = mk_url("style")
@staticmethod
def check(root: Traversable) -> bool:
"Projects must have a `.pre-commit-config.yaml` file"
return root.joinpath(".pre-commit-config.yaml").is_file()
class PY007(General):
"Supports an easy task runner (nox or tox)"
url = mk_url("tasks")
@staticmethod
def check(root: Traversable, pyproject: dict[str, Any]) -> bool:
"""
Projects must have a `noxfile.py`, `tox.ini`, or
`tool.hatch.envs`/`tool.spin`/`tool.tox` in `pyproject.toml` to encourage new
contributors.
"""
if root.joinpath("noxfile.py").is_file():
return True
if root.joinpath("tox.ini").is_file():
return True
match pyproject.get("tool", {}):
case {"hatch": {"envs": object()}}:
return True
case {"spin": object()}:
return True
case {"tox": object()}:
return True
case _:
return False
def repo_review_checks() -> dict[str, General]:
return {p.__name__: p() for p in General.__subclasses__()}