[ci] enable ruff-format on some files, add pre-commit config (#6308)

This commit is contained in:
James Lamb 2024-02-14 22:17:35 -06:00 коммит произвёл GitHub
Родитель cc733f8595
Коммит 6330d6269c
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: B5690EEEBB952194
10 изменённых файлов: 207 добавлений и 171 удалений

Просмотреть файл

@ -32,25 +32,26 @@ def get_runs(trigger_phrase):
"""
pr_runs = []
if environ.get("GITHUB_EVENT_NAME", "") == "pull_request":
pr_number = int(environ.get("GITHUB_REF").split('/')[-2])
pr_number = int(environ.get("GITHUB_REF").split("/")[-2])
page = 1
while True:
req = request.Request(
url="{}/repos/microsoft/LightGBM/issues/{}/comments?page={}&per_page=100".format(
environ.get("GITHUB_API_URL"),
pr_number,
page
environ.get("GITHUB_API_URL"), pr_number, page
),
headers={"Accept": "application/vnd.github.v3+json"}
headers={"Accept": "application/vnd.github.v3+json"},
)
url = request.urlopen(req)
data = json.loads(url.read().decode('utf-8'))
data = json.loads(url.read().decode("utf-8"))
url.close()
if not data:
break
runs_on_page = [i for i in data
if i['author_association'].lower() in {'owner', 'member', 'collaborator'}
and i['body'].startswith('/gha run {}'.format(trigger_phrase))]
runs_on_page = [
i
for i in data
if i["author_association"].lower() in {"owner", "member", "collaborator"}
and i["body"].startswith("/gha run {}".format(trigger_phrase))
]
pr_runs.extend(runs_on_page)
page += 1
return pr_runs[::-1]
@ -70,20 +71,20 @@ def get_status(runs):
The most recent status of workflow.
Can be 'success', 'failure' or 'in-progress'.
"""
status = 'success'
status = "success"
for run in runs:
body = run['body']
body = run["body"]
if "Status: " in body:
if "Status: skipped" in body:
continue
if "Status: failure" in body:
status = 'failure'
status = "failure"
break
if "Status: success" in body:
status = 'success'
status = "success"
break
else:
status = 'in-progress'
status = "in-progress"
break
return status
@ -92,8 +93,8 @@ if __name__ == "__main__":
trigger_phrase = argv[1]
while True:
status = get_status(get_runs(trigger_phrase))
if status != 'in-progress':
if status != "in-progress":
break
sleep(60)
if status == 'failure':
if status == "failure":
exit(1)

Просмотреть файл

@ -1,19 +1,8 @@
#!/bin/sh
echo "running ruff"
ruff check \
--config=./python-package/pyproject.toml \
. \
|| exit 1
echo "done running ruff"
echo "running isort"
isort \
--check-only \
--settings-path=./python-package/pyproject.toml \
. \
|| exit 1
echo "done running isort"
echo "running pre-commit checks"
pre-commit run --all-files || exit 1
echo "done running pre-commit checks"
echo "running mypy"
mypy \

Просмотреть файл

@ -74,10 +74,9 @@ if [[ $TASK == "lint" ]]; then
${CONDA_PYTHON_REQUIREMENT} \
cmakelint \
cpplint \
isort \
mypy \
'r-lintr>=3.1' \
ruff
'pre-commit>=3.6.0' \
'r-lintr>=3.1'
source activate $CONDA_ENV
echo "Linting Python code"
sh ${BUILD_DIRECTORY}/.ci/lint-python.sh || exit 1

Просмотреть файл

@ -20,7 +20,7 @@ if __name__ == "__main__":
copyfile(source / "lib_lightgbm.dylib", osx_folder_path / "lib_lightgbm.dylib")
copyfile(source / "lib_lightgbm.dll", windows_folder_path / "lib_lightgbm.dll")
copyfile(source / "lightgbm.exe", windows_folder_path / "lightgbm.exe")
version = (current_dir.parent / 'VERSION.txt').read_text(encoding='utf-8').strip().replace('rc', '-rc')
version = (current_dir.parent / "VERSION.txt").read_text(encoding="utf-8").strip().replace("rc", "-rc")
nuget_str = rf"""<?xml version="1.0"?>
<package xmlns="http://schemas.microsoft.com/packaging/2013/05/nuspec.xsd">
<metadata>
@ -75,6 +75,6 @@ if __name__ == "__main__":
</Target>
</Project>
"""
(current_dir / "LightGBM.nuspec").write_text(nuget_str, encoding='utf-8')
(current_dir / "build" / "LightGBM.props").write_text(prop_str, encoding='utf-8')
(current_dir / "build" / "LightGBM.targets").write_text(target_str, encoding='utf-8')
(current_dir / "LightGBM.nuspec").write_text(nuget_str, encoding="utf-8")
(current_dir / "build" / "LightGBM.props").write_text(prop_str, encoding="utf-8")
(current_dir / "build" / "LightGBM.targets").write_text(target_str, encoding="utf-8")

25
.pre-commit-config.yaml Normal file
Просмотреть файл

@ -0,0 +1,25 @@
exclude: |
(?x)^(
build|
external_libs|
lightgbm-python|
lightgbm_r|
)$
repos:
- repo: https://github.com/astral-sh/ruff-pre-commit
# Ruff version.
rev: v0.2.1
hooks:
# Run the linter.
- id: ruff
args: ["--config", "python-package/pyproject.toml"]
# Run the formatter.
- id: ruff-format
args: ["--config", "python-package/pyproject.toml"]
- repo: https://github.com/pycqa/isort
rev: 5.13.2
hooks:
- id: isort
name: isort (python)
args: ["--settings-path", "python-package/pyproject.toml"]

Просмотреть файл

@ -1,4 +1,10 @@
LightGBM has been developed and used by many active community members. Your help is very valuable to make it better for everyone.
# contributing
LightGBM has been developed and used by many active community members.
Your help is very valuable to make it better for everyone.
## How to Contribute
- Check for the [Roadmap](https://github.com/microsoft/LightGBM/projects/1) and the [Feature Requests Hub](https://github.com/microsoft/LightGBM/issues/2302), and submit pull requests to address chosen issue. If you need development guideline, you can check the [Development Guide](https://github.com/microsoft/LightGBM/blob/master/docs/Development-Guide.rst) or directly ask us in Issues/Pull Requests.
- Contribute to the [tests](https://github.com/microsoft/LightGBM/tree/master/tests) to make it more reliable.
@ -6,3 +12,17 @@ LightGBM has been developed and used by many active community members. Your help
- Contribute to the [examples](https://github.com/microsoft/LightGBM/tree/master/examples) to share your experience with other users.
- Add your stories and experience to [Awesome LightGBM](https://github.com/microsoft/LightGBM/blob/master/examples/README.md). If LightGBM helped you in a machine learning competition or some research application, we want to hear about it!
- [Open an issue](https://github.com/microsoft/LightGBM/issues) to report problems or recommend new features.
## Development Guide
### Linting
Every commit in the repository is tested with multiple static analyzers.
When developing locally, run some of them using `pre-commit` ([pre-commit docs](https://pre-commit.com/)).
```shell
pre-commit run --all-files
```
That command will check for some issues and automatically reformat the code.

Просмотреть файл

@ -34,7 +34,7 @@ from sphinx.application import Sphinx
from sphinx.errors import VersionRequirementError
CURR_PATH = Path(__file__).absolute().parent
LIB_PATH = CURR_PATH.parent / 'python-package'
LIB_PATH = CURR_PATH.parent / "python-package"
sys.path.insert(0, str(LIB_PATH))
INTERNAL_REF_REGEX = compile(r"(?P<url>\.\/.+)(?P<extension>\.rst)(?P<anchor>$|#)")
@ -65,29 +65,29 @@ class IgnoredDirective(Directive):
# -- General configuration ------------------------------------------------
os.environ['LIGHTGBM_BUILD_DOC'] = '1'
C_API = os.environ.get('C_API', '').lower().strip() != 'no'
RTD = bool(os.environ.get('READTHEDOCS', ''))
os.environ["LIGHTGBM_BUILD_DOC"] = "1"
C_API = os.environ.get("C_API", "").lower().strip() != "no"
RTD = bool(os.environ.get("READTHEDOCS", ""))
# If your documentation needs a minimal Sphinx version, state it here.
needs_sphinx = '2.1.0' # Due to sphinx.ext.napoleon, autodoc_typehints
needs_sphinx = "2.1.0" # Due to sphinx.ext.napoleon, autodoc_typehints
if needs_sphinx > sphinx.__version__:
message = f'This project needs at least Sphinx v{needs_sphinx}'
message = f"This project needs at least Sphinx v{needs_sphinx}"
raise VersionRequirementError(message)
# Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
# ones.
extensions = [
'sphinx.ext.autodoc',
'sphinx.ext.autosummary',
'sphinx.ext.todo',
'sphinx.ext.viewcode',
'sphinx.ext.napoleon',
"sphinx.ext.autodoc",
"sphinx.ext.autosummary",
"sphinx.ext.todo",
"sphinx.ext.viewcode",
"sphinx.ext.napoleon",
"sphinx.ext.intersphinx",
]
autodoc_default_flags = ['members', 'inherited-members', 'show-inheritance']
autodoc_default_flags = ["members", "inherited-members", "show-inheritance"]
autodoc_default_options = {
"members": True,
"inherited-members": True,
@ -95,54 +95,54 @@ autodoc_default_options = {
}
# mock out modules
autodoc_mock_imports = [
'dask',
'dask.distributed',
'datatable',
'graphviz',
'matplotlib',
'numpy',
'pandas',
'scipy',
'scipy.sparse',
"dask",
"dask.distributed",
"datatable",
"graphviz",
"matplotlib",
"numpy",
"pandas",
"scipy",
"scipy.sparse",
]
try:
import sklearn # noqa: F401
except ImportError:
autodoc_mock_imports.append('sklearn')
autodoc_mock_imports.append("sklearn")
# hide type hints in API docs
autodoc_typehints = "none"
# Generate autosummary pages. Output should be set with: `:toctree: pythonapi/`
autosummary_generate = ['Python-API.rst']
autosummary_generate = ["Python-API.rst"]
# Only the class' docstring is inserted.
autoclass_content = 'class'
autoclass_content = "class"
# If true, `todo` and `todoList` produce output, else they produce nothing.
todo_include_todos = False
# The master toctree document.
master_doc = 'index'
master_doc = "index"
# General information about the project.
project = 'LightGBM'
copyright = f'{datetime.datetime.now().year}, Microsoft Corporation'
author = 'Microsoft Corporation'
project = "LightGBM"
copyright = f"{datetime.datetime.now().year}, Microsoft Corporation"
author = "Microsoft Corporation"
# The name of an image file (relative to this directory) to place at the top
# of the sidebar.
html_logo = str(CURR_PATH / 'logo' / 'LightGBM_logo_grey_text.svg')
html_logo = str(CURR_PATH / "logo" / "LightGBM_logo_grey_text.svg")
# The name of an image file (relative to this directory) to use as a favicon of
# the docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
# pixels large.
html_favicon = str(CURR_PATH / '_static' / 'images' / 'favicon.ico')
html_favicon = str(CURR_PATH / "_static" / "images" / "favicon.ico")
# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
# built documents.
# The short X.Y version.
version = (CURR_PATH.parent / 'VERSION.txt').read_text(encoding='utf-8').strip().replace('rc', '-rc')
version = (CURR_PATH.parent / "VERSION.txt").read_text(encoding="utf-8").strip().replace("rc", "-rc")
# The full version, including alpha/beta/rc tags.
release = version
@ -151,67 +151,68 @@ release = version
#
# This is also used if you do content translation via gettext catalogs.
# Usually you set "language" from the command line for these cases.
language = 'en'
language = "en"
# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
# This patterns also effect to html_static_path and html_extra_path
exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"]
# The name of the Pygments (syntax highlighting) style to use.
pygments_style = 'default'
pygments_style = "default"
# -- Configuration for C API docs generation ------------------------------
if C_API:
extensions.extend([
'breathe',
])
breathe_projects = {
"LightGBM": str(CURR_PATH / 'doxyoutput' / 'xml')
}
extensions.extend(
[
"breathe",
]
)
breathe_projects = {"LightGBM": str(CURR_PATH / "doxyoutput" / "xml")}
breathe_default_project = "LightGBM"
breathe_domain_by_extension = {
"h": "c",
}
breathe_show_define_initializer = True
c_id_attributes = ['LIGHTGBM_C_EXPORT']
c_id_attributes = ["LIGHTGBM_C_EXPORT"]
# -- Options for HTML output ----------------------------------------------
# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
html_theme = 'sphinx_rtd_theme'
html_theme = "sphinx_rtd_theme"
# Theme options are theme-specific and customize the look and feel of a theme
# further. For a list of options available for each theme, see the
# documentation.
html_theme_options = {
'includehidden': False,
'logo_only': True,
"includehidden": False,
"logo_only": True,
}
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ['_static']
html_static_path = ["_static"]
# -- Options for HTMLHelp output ------------------------------------------
# Output file base name for HTML help builder.
htmlhelp_basename = 'LightGBMdoc'
htmlhelp_basename = "LightGBMdoc"
# -- Options for LaTeX output ---------------------------------------------
# The name of an image file (relative to this directory) to place at the top of
# the title page.
latex_logo = str(CURR_PATH / 'logo' / 'LightGBM_logo_black_text_small.png')
latex_logo = str(CURR_PATH / "logo" / "LightGBM_logo_black_text_small.png")
# intersphinx configuration
intersphinx_mapping = {
"sklearn": ("https://scikit-learn.org/stable/", None),
}
def generate_doxygen_xml(app: Sphinx) -> None:
"""Generate XML documentation for C API by Doxygen.
@ -238,18 +239,17 @@ def generate_doxygen_xml(app: Sphinx) -> None:
"SORT_BRIEF_DOCS=YES",
"WARN_AS_ERROR=YES",
]
doxygen_input = '\n'.join(doxygen_args)
doxygen_input = "\n".join(doxygen_args)
doxygen_input = bytes(doxygen_input, "utf-8")
(CURR_PATH / 'doxyoutput').mkdir(parents=True, exist_ok=True)
(CURR_PATH / "doxyoutput").mkdir(parents=True, exist_ok=True)
try:
# Warning! The following code can cause buffer overflows on RTD.
# Consider suppressing output completely if RTD project silently fails.
# Refer to https://github.com/svenevs/exhale
# /blob/fe7644829057af622e467bb529db6c03a830da99/exhale/deploy.py#L99-L111
process = Popen(["doxygen", "-"],
stdin=PIPE, stdout=PIPE, stderr=PIPE)
process = Popen(["doxygen", "-"], stdin=PIPE, stdout=PIPE, stderr=PIPE)
stdout, stderr = process.communicate(doxygen_input)
output = '\n'.join([i.decode('utf-8') for i in (stdout, stderr) if i is not None])
output = "\n".join([i.decode("utf-8") for i in (stdout, stderr) if i is not None])
if process.returncode != 0:
raise RuntimeError(output)
else:
@ -296,11 +296,9 @@ def generate_r_docs(app: Sphinx) -> None:
# Consider suppressing output completely if RTD project silently fails.
# Refer to https://github.com/svenevs/exhale
# /blob/fe7644829057af622e467bb529db6c03a830da99/exhale/deploy.py#L99-L111
process = Popen(['/bin/bash'],
stdin=PIPE, stdout=PIPE, stderr=PIPE,
universal_newlines=True)
process = Popen(["/bin/bash"], stdin=PIPE, stdout=PIPE, stderr=PIPE, universal_newlines=True)
stdout, stderr = process.communicate(commands)
output = '\n'.join([i for i in (stdout, stderr) if i is not None])
output = "\n".join([i for i in (stdout, stderr) if i is not None])
if process.returncode != 0:
raise RuntimeError(output)
else:
@ -318,19 +316,19 @@ def setup(app: Sphinx) -> None:
app : sphinx.application.Sphinx
The application object representing the Sphinx process.
"""
first_run = not (CURR_PATH / '_FIRST_RUN.flag').exists()
first_run = not (CURR_PATH / "_FIRST_RUN.flag").exists()
if first_run and RTD:
(CURR_PATH / '_FIRST_RUN.flag').touch()
(CURR_PATH / "_FIRST_RUN.flag").touch()
if C_API:
app.connect("builder-inited", generate_doxygen_xml)
else:
app.add_directive('doxygenfile', IgnoredDirective)
app.add_directive("doxygenfile", IgnoredDirective)
if RTD: # build R docs only on Read the Docs site
if first_run:
app.connect("builder-inited", generate_r_docs)
app.connect("build-finished",
lambda app, _: copytree(CURR_PATH.parent / "lightgbm_r" / "docs",
Path(app.outdir) / "R"))
app.connect(
"build-finished", lambda app, _: copytree(CURR_PATH.parent / "lightgbm_r" / "docs", Path(app.outdir) / "R")
)
app.add_transform(InternalRefTransform)
add_js_file = getattr(app, 'add_js_file', False) or app.add_javascript
add_js_file = getattr(app, "add_js_file", False) or app.add_javascript
add_js_file("js/script.js")

Просмотреть файл

@ -25,7 +25,7 @@ def check_dependencies(objdump_string: str) -> None:
objdump_string : str
The dynamic symbol table entries of the file (result of `objdump -T` command).
"""
GLIBC_version = re.compile(r'0{16}[ \(\t]+GLIBC_(\d{1,2})[.](\d{1,3})[.]?\d{,3}[ \)\t]+')
GLIBC_version = re.compile(r"0{16}[ \(\t]+GLIBC_(\d{1,2})[.](\d{1,3})[.]?\d{,3}[ \)\t]+")
versions = GLIBC_version.findall(objdump_string)
assert len(versions) > 1
for major, minor in versions:
@ -33,16 +33,16 @@ def check_dependencies(objdump_string: str) -> None:
assert int(major) <= 2, error_msg
assert int(minor) <= 28, error_msg
GLIBCXX_version = re.compile(r'0{16}[ \(\t]+GLIBCXX_(\d{1,2})[.](\d{1,2})[.]?(\d{,3})[ \)\t]+')
GLIBCXX_version = re.compile(r"0{16}[ \(\t]+GLIBCXX_(\d{1,2})[.](\d{1,2})[.]?(\d{,3})[ \)\t]+")
versions = GLIBCXX_version.findall(objdump_string)
assert len(versions) > 1
for major, minor, patch in versions:
error_msg = f"found unexpected GLIBCXX version: '{major}.{minor}.{patch}'"
assert int(major) == 3, error_msg
assert int(minor) == 4, error_msg
assert patch == '' or int(patch) <= 22, error_msg
assert patch == "" or int(patch) <= 22, error_msg
GOMP_version = re.compile(r'0{16}[ \(\t]+G?OMP_(\d{1,2})[.](\d{1,2})[.]?\d{,3}[ \)\t]+')
GOMP_version = re.compile(r"0{16}[ \(\t]+G?OMP_(\d{1,2})[.](\d{1,2})[.]?\d{,3}[ \)\t]+")
versions = GOMP_version.findall(objdump_string)
assert len(versions) > 1
for major, minor in versions:
@ -52,4 +52,4 @@ def check_dependencies(objdump_string: str) -> None:
if __name__ == "__main__":
check_dependencies(Path(sys.argv[1]).read_text(encoding='utf-8'))
check_dependencies(Path(sys.argv[1]).read_text(encoding="utf-8"))

Просмотреть файл

@ -12,9 +12,7 @@ from pathlib import Path
from typing import Dict, List, Tuple
def get_parameter_infos(
config_hpp: Path
) -> Tuple[List[Tuple[str, int]], List[List[Dict[str, List]]]]:
def get_parameter_infos(config_hpp: Path) -> Tuple[List[Tuple[str, int]], List[List[Dict[str, List]]]]:
"""Parse config header file.
Parameters
@ -44,7 +42,7 @@ def get_parameter_infos(
cur_key = line.split("region")[1].strip()
keys.append((cur_key, key_lvl))
member_infos.append([])
elif '#pragma endregion' in line:
elif "#pragma endregion" in line:
key_lvl -= 1
if cur_key is not None:
cur_key = None
@ -87,9 +85,7 @@ def get_parameter_infos(
return keys, member_infos
def get_names(
infos: List[List[Dict[str, List]]]
) -> List[str]:
def get_names(infos: List[List[Dict[str, List]]]) -> List[str]:
"""Get names of all parameters.
Parameters
@ -109,9 +105,7 @@ def get_names(
return names
def get_alias(
infos: List[List[Dict[str, List]]]
) -> List[Tuple[str, str]]:
def get_alias(infos: List[List[Dict[str, List]]]) -> List[Tuple[str, str]]:
"""Get aliases of all parameters.
Parameters
@ -129,16 +123,13 @@ def get_alias(
for y in x:
if "alias" in y:
name = y["name"][0]
alias = y["alias"][0].split(',')
alias = y["alias"][0].split(",")
for name2 in alias:
pairs.append((name2.strip(), name))
return pairs
def parse_check(
check: str,
reverse: bool = False
) -> Tuple[str, str]:
def parse_check(check: str, reverse: bool = False) -> Tuple[str, str]:
"""Parse the constraint.
Parameters
@ -160,17 +151,13 @@ def parse_check(
idx = 2
float(check[idx:])
if reverse:
reversed_sign = {'<': '>', '>': '<', '<=': '>=', '>=': '<='}
reversed_sign = {"<": ">", ">": "<", "<=": ">=", ">=": "<="}
return check[idx:], reversed_sign[check[:idx]]
else:
return check[idx:], check[:idx]
def set_one_var_from_string(
name: str,
param_type: str,
checks: List[str]
) -> str:
def set_one_var_from_string(name: str, param_type: str, checks: List[str]) -> str:
"""Construct code for auto config file for one param value.
Parameters
@ -209,9 +196,7 @@ def set_one_var_from_string(
def gen_parameter_description(
sections: List[Tuple[str, int]],
descriptions: List[List[Dict[str, List]]],
params_rst: Path
sections: List[Tuple[str, int]], descriptions: List[List[Dict[str, List]]], params_rst: Path
) -> None:
"""Write descriptions of parameters to the documentation file.
@ -225,58 +210,57 @@ def gen_parameter_description(
Path to the file with parameters documentation.
"""
params_to_write = []
lvl_mapper = {1: '-', 2: '~'}
lvl_mapper = {1: "-", 2: "~"}
for (section_name, section_lvl), section_params in zip(sections, descriptions):
heading_sign = lvl_mapper[section_lvl]
params_to_write.append(f'{section_name}\n{heading_sign * len(section_name)}')
params_to_write.append(f"{section_name}\n{heading_sign * len(section_name)}")
for param_desc in section_params:
name = param_desc['name'][0]
default_raw = param_desc['default'][0]
name = param_desc["name"][0]
default_raw = param_desc["default"][0]
default = default_raw.strip('"') if len(default_raw.strip('"')) > 0 else default_raw
param_type = param_desc.get('type', param_desc['inner_type'])[0].split(':')[-1].split('<')[-1].strip('>')
options = param_desc.get('options', [])
param_type = param_desc.get("type", param_desc["inner_type"])[0].split(":")[-1].split("<")[-1].strip(">")
options = param_desc.get("options", [])
if len(options) > 0:
opts = '``, ``'.join([x.strip() for x in options[0].split(',')])
options_str = f', options: ``{opts}``'
opts = "``, ``".join([x.strip() for x in options[0].split(",")])
options_str = f", options: ``{opts}``"
else:
options_str = ''
aliases = param_desc.get('alias', [])
options_str = ""
aliases = param_desc.get("alias", [])
if len(aliases) > 0:
aliases_joined = '``, ``'.join([x.strip() for x in aliases[0].split(',')])
aliases_str = f', aliases: ``{aliases_joined}``'
aliases_joined = "``, ``".join([x.strip() for x in aliases[0].split(",")])
aliases_str = f", aliases: ``{aliases_joined}``"
else:
aliases_str = ''
checks = sorted(param_desc.get('check', []))
aliases_str = ""
checks = sorted(param_desc.get("check", []))
checks_len = len(checks)
if checks_len > 1:
number1, sign1 = parse_check(checks[0])
number2, sign2 = parse_check(checks[1], reverse=True)
checks_str = f', constraints: ``{number2} {sign2} {name} {sign1} {number1}``'
checks_str = f", constraints: ``{number2} {sign2} {name} {sign1} {number1}``"
elif checks_len == 1:
number, sign = parse_check(checks[0])
checks_str = f', constraints: ``{name} {sign} {number}``'
checks_str = f", constraints: ``{name} {sign} {number}``"
else:
checks_str = ''
checks_str = ""
main_desc = f'- ``{name}`` :raw-html:`<a id="{name}" title="Permalink to this parameter" href="#{name}">&#x1F517;&#xFE0E;</a>`, default = ``{default}``, type = {param_type}{options_str}{aliases_str}{checks_str}'
params_to_write.append(main_desc)
params_to_write.extend([f"{' ' * 3 * int(desc[0][-1])}- {desc[1]}" for desc in param_desc['desc']])
params_to_write.extend([f"{' ' * 3 * int(desc[0][-1])}- {desc[1]}" for desc in param_desc["desc"]])
with open(params_rst) as original_params_file:
all_lines = original_params_file.read()
before, start_sep, _ = all_lines.partition('.. start params list\n\n')
_, end_sep, after = all_lines.partition('\n\n.. end params list')
before, start_sep, _ = all_lines.partition(".. start params list\n\n")
_, end_sep, after = all_lines.partition("\n\n.. end params list")
with open(params_rst, "w") as new_params_file:
new_params_file.write(before)
new_params_file.write(start_sep)
new_params_file.write('\n\n'.join(params_to_write))
new_params_file.write("\n\n".join(params_to_write))
new_params_file.write(end_sep)
new_params_file.write(after)
def gen_parameter_code(
config_hpp: Path,
config_out_cpp: Path
config_hpp: Path, config_out_cpp: Path
) -> Tuple[List[Tuple[str, int]], List[List[Dict[str, List]]]]:
"""Generate auto config file.
@ -367,7 +351,7 @@ def gen_parameter_code(
if names_with_aliases[name]:
str_to_write += '{"' + '", "'.join(names_with_aliases[name]) + '"}},'
else:
str_to_write += '{}},'
str_to_write += "{}},"
str_to_write += """
});
return map;
@ -376,22 +360,22 @@ def gen_parameter_code(
"""
str_to_write += """const std::unordered_map<std::string, std::string>& Config::ParameterTypes() {
static std::unordered_map<std::string, std::string> map({"""
int_t_pat = re.compile(r'int\d+_t')
int_t_pat = re.compile(r"int\d+_t")
# the following are stored as comma separated strings but are arrays in the wrappers
overrides = {
'categorical_feature': 'vector<int>',
'ignore_column': 'vector<int>',
'interaction_constraints': 'vector<vector<int>>',
"categorical_feature": "vector<int>",
"ignore_column": "vector<int>",
"interaction_constraints": "vector<vector<int>>",
}
for x in infos:
for y in x:
name = y["name"][0]
if name == 'task':
if name == "task":
continue
if name in overrides:
param_type = overrides[name]
else:
param_type = int_t_pat.sub('int', y["inner_type"][0]).replace('std::', '')
param_type = int_t_pat.sub("int", y["inner_type"][0]).replace("std::", "")
str_to_write += '\n {"' + name + '", "' + param_type + '"},'
str_to_write += """
});
@ -409,8 +393,8 @@ def gen_parameter_code(
if __name__ == "__main__":
current_dir = Path(__file__).absolute().parent
config_hpp = current_dir.parent / 'include' / 'LightGBM' / 'config.h'
config_out_cpp = current_dir.parent / 'src' / 'io' / 'config_auto.cpp'
params_rst = current_dir.parent / 'docs' / 'Parameters.rst'
config_hpp = current_dir.parent / "include" / "LightGBM" / "config.h"
config_out_cpp = current_dir.parent / "src" / "io" / "config_auto.cpp"
params_rst = current_dir.parent / "docs" / "Parameters.rst"
sections, descriptions = gen_parameter_code(config_hpp, config_out_cpp)
gen_parameter_description(sections, descriptions, params_rst)

Просмотреть файл

@ -95,11 +95,29 @@ ignore_missing_imports = true
exclude = [
"build",
"compile",
"docs",
"external_libs",
"lightgbm-python",
"setup.py"
]
line-length = 120
# this should be set to the oldest version of python LightGBM supports
target-version = "py37"
[tool.ruff.format]
docstring-code-format = false
exclude = [
"build/*.py",
"compile/*.py",
"examples/*.py",
"external_libs/*.py",
"lightgbm-python/*.py",
"python-package/*.py",
"tests/*.py"
]
indent-style = "space"
quote-style = "double"
[tool.ruff.lint]
ignore = [
# (pydocstyle) Missing docstring in magic method
"D105",
@ -125,10 +143,13 @@ select = [
"T",
]
# this should be set to the oldest version of python LightGBM supports
target-version = "py37"
[tool.ruff.per-file-ignores]
[tool.ruff.lint.per-file-ignores]
"docs/conf.py" = [
# (flake8-bugbear) raise exceptions with "raise ... from errr"
"B904",
# (flake8-print) flake8-print
"T"
]
"examples/*" = [
# pydocstyle
"D",
@ -144,6 +165,5 @@ target-version = "py37"
"T"
]
[tool.ruff.pydocstyle]
[tool.ruff.lint.pydocstyle]
convention = "numpy"