From 4b90e4d7d88a84d94b556e7ba4c28919e0d50d8b Mon Sep 17 00:00:00 2001 From: Daniel Holth Date: Mon, 27 Mar 2023 13:49:13 -0400 Subject: [PATCH 01/11] add sphinx-argparse documentation --- .github/workflows/sphinx.yml | 53 +++++ .gitignore | 2 +- docs/requirements.txt | 6 + docs/source/cli.md | 9 + docs/source/conf.py | 6 +- docs/source/index.rst | 1 + grayskull/__main__.py | 388 +--------------------------------- grayskull/main.py | 393 +++++++++++++++++++++++++++++++++++ pyproject.toml | 21 +- 9 files changed, 482 insertions(+), 397 deletions(-) create mode 100644 .github/workflows/sphinx.yml create mode 100644 docs/requirements.txt create mode 100644 docs/source/cli.md create mode 100644 grayskull/main.py diff --git a/.github/workflows/sphinx.yml b/.github/workflows/sphinx.yml new file mode 100644 index 000000000..717b3bcba --- /dev/null +++ b/.github/workflows/sphinx.yml @@ -0,0 +1,53 @@ +name: Sphinx +on: + push: + branches: + - main + + pull_request: + branches: + - main + +jobs: + sphinx: + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-python@v4 + with: + python-version: "3.x" + architecture: "x64" + cache: "pip" + - name: Build Documentation + run: | + pip install -e .[docs] + pip install -r docs/requirements.txt # redundant? + make html + - name: Upload artifact + uses: actions/upload-pages-artifact@v1 + with: + # Upload entire repository + path: 'build/html' + + pages: + + runs-on: ubuntu-latest + if: github.ref == 'refs/heads/main' + needs: [sphinx] + + # Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages + permissions: + contents: read + pages: write + id-token: write + + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + + steps: + - name: Deploy to GitHub Pages + id: deployment + uses: actions/deploy-pages@v1 diff --git a/.gitignore b/.gitignore index 1d93a6836..1be763906 100644 --- a/.gitignore +++ b/.gitignore @@ -69,7 +69,7 @@ instance/ .scrapy # Sphinx documentation -docs/_build/ +docs/build/ # PyBuilder target/ diff --git a/docs/requirements.txt b/docs/requirements.txt new file mode 100644 index 000000000..f5e61070a --- /dev/null +++ b/docs/requirements.txt @@ -0,0 +1,6 @@ +# docs +furo +sphinx +sphinx-argparse +myst-parser +mdit-py-plugins>=0.3.0 diff --git a/docs/source/cli.md b/docs/source/cli.md new file mode 100644 index 000000000..159c70c56 --- /dev/null +++ b/docs/source/cli.md @@ -0,0 +1,9 @@ +Command Line +============ + +```{eval-rst} +.. argparse:: + :module: grayskull.main + :func: build_parser + :prog: grayskull +``` diff --git a/docs/source/conf.py b/docs/source/conf.py index bb0d2f1cc..65eb8ff05 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -30,7 +30,11 @@ # Add any Sphinx extension module names here, as strings. They can be # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. -extensions = [] +extensions = [ + "sphinx.ext.autodoc", + "sphinxarg.ext", + "myst_parser", +] # Add any paths that contain templates here, relative to this directory. templates_path = ["_templates"] diff --git a/docs/source/index.rst b/docs/source/index.rst index 2eba6d8d6..bc15fb2ec 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -20,6 +20,7 @@ Grayskull Documentation :caption: Contents: user_guide + cli developer_guide diff --git a/grayskull/__main__.py b/grayskull/__main__.py index e3e225ac9..3cf16f9f6 100644 --- a/grayskull/__main__.py +++ b/grayskull/__main__.py @@ -1,390 +1,4 @@ -import argparse -import logging -import os -import sys -from pathlib import Path -from typing import List, Optional - -import requests -from colorama import Fore, Style, init -from colorama.ansi import clear_screen - -import grayskull -from grayskull.base.factory import GrayskullFactory -from grayskull.base.github import get_git_current_user -from grayskull.cli import CLIConfig -from grayskull.cli.stdout import print_msg -from grayskull.config import Configuration -from grayskull.utils import generate_recipe, origin_is_github, origin_is_local_sdist - -init(autoreset=True) -logging.basicConfig(format="%(levelname)s:%(message)s") - - -def main(args=None): - if not args: - args = sys.argv[1:] or ["--help"] - - # create the top-level parser - parser = argparse.ArgumentParser(description="Grayskull - Conda recipe generator") - subparsers = parser.add_subparsers(help="sub-command help") - # create parser for cran - cran_parser = subparsers.add_parser("cran", help="Options to generate CRAN recipes") - cran_parser.add_argument( - "cran_packages", nargs="+", help="Specify the CRAN packages name.", default=[] - ) - cran_parser.add_argument( - "--stdout", - dest="stdout", - default=True, - help="Disable or enable stdout, if it is False, Grayskull" - " will disable the prints. Default is True", - ) - cran_parser.add_argument( - "--list-missing-deps", - default=False, - action="store_true", - dest="list_missing_deps", - help="After the execution Grayskull will print all the missing dependencies.", - ) - cran_parser.add_argument( - "--download", - "-d", - dest="download", - action="store_true", - default=False, - help="Download the sdist package and PyPI information in the same folder" - " the recipe is located.", - ) - cran_parser.add_argument( - "--maintainers", - "-m", - dest="maintainers", - nargs="+", - help="List of maintainers which will be added to the recipe.", - ) - cran_parser.add_argument( - "--output", - "-o", - dest="output", - default=".", - help="Path to where the recipe will be created", - ) - cran_parser.add_argument( - "--strict-conda-forge", - default=False, - action="store_true", - dest="is_strict_conda_forge", - help="It will generate the recipes strict for the conda-forge channel.", - ) - cran_parser.add_argument( - "--sections", - "-s", - default=None, - required=False, - choices=( - "package", - "source", - "build", - "requirements", - "test", - "about", - "extra", - ), - nargs="+", - dest="sections_populate", - help="If sections are specified, grayskull will populate just the sections " - "informed.", - ) - # create parser for pypi - pypi_parser = subparsers.add_parser("pypi", help="Options to generate PyPI recipes") - pypi_parser.add_argument( - "pypi_packages", nargs="+", help="Specify the PyPI packages name.", default=[] - ) - pypi_parser.add_argument( - "--download", - "-d", - dest="download", - action="store_true", - default=False, - help="Download the sdist package and PyPI information in the same folder" - " the recipe is located.", - ) - pypi_parser.add_argument( - "--maintainers", - "-m", - dest="maintainers", - nargs="+", - help="List of maintainers which will be added to the recipe.", - ) - parser.add_argument( - "--version", - "-v", - default=False, - action="store_true", - dest="version", - help="Print Grayskull version and exit", - ) - parser.add_argument( - "--heman", - "--shera", - default=False, - action="store_true", - dest="grayskull_power", - help=argparse.SUPPRESS, - ) - pypi_parser.add_argument( - "--output", - "-o", - dest="output", - default=".", - help="Path to where the recipe will be created", - ) - pypi_parser.add_argument( - "--stdout", - dest="stdout", - default=True, - help="Disable or enable stdout, if it is False, Grayskull" - " will disable the prints. Default is True", - ) - pypi_parser.add_argument( - "--list-missing-deps", - default=False, - action="store_true", - dest="list_missing_deps", - help="After the execution Grayskull will print all the missing dependencies.", - ) - pypi_parser.add_argument( - "--strict-conda-forge", - default=False, - action="store_true", - dest="is_strict_conda_forge", - help="It will generate the recipes strict for the conda-forge channel.", - ) - pypi_parser.add_argument( - "--pypi-url", - default="https://pypi.org/pypi/", - dest="url_pypi_metadata", - help="Pypi url server", - ) - pypi_parser.add_argument( - "--recursive", - "-r", - default=False, - action="store_true", - dest="is_recursive", - help="Recursively run grayskull on missing dependencies.", - ) - pypi_parser.add_argument( - "--sections", - "-s", - default=None, - required=False, - choices=( - "package", - "source", - "build", - "requirements", - "test", - "about", - "extra", - ), - nargs="+", - dest="sections_populate", - help="If sections are specified, grayskull will populate just the sections " - "informed.", - ) - pypi_parser.add_argument( - "--extras-require-test", - default=None, - dest="extras_require_test", - help="Extra requirements to run tests.", - ) - pypi_parser.add_argument( - "--tag", - "-t", - default=None, - dest="github_release_tag", - help="If tag is specified, grayskull will build from release tag", - ) - pypi_parser.add_argument( - "--extras-require-all", - default=False, - action="store_true", - dest="extras_require_all", - help="Include all extra requirements.", - ) - pypi_parser.add_argument( - "--extras-require-include", - default=tuple(), - type=str, - nargs="*", - dest="extras_require_include", - help="Include these extra requirements.", - ) - pypi_parser.add_argument( - "--extras-require-exclude", - default=tuple(), - type=str, - nargs="*", - dest="extras_require_exclude", - help="Exclude these extra requirements (overrides include).", - ) - pypi_parser.add_argument( - "--extras-require-split", - default=False, - action="store_true", - dest="extras_require_split", - help="Create a separate conda package for each extra requirements." - " Ignored when no extra requirements are selected.", - ) - pypi_parser.add_argument( - "--licence-exclude-folders", - default=tuple(), - nargs="*", - dest="licence_exclude_folders", - help="Exclude folders when searching for licence.", - ) - - args = parser.parse_args(args) - - if args.version: - print(grayskull.__version__) - return - - logging.debug(f"All arguments received: args: {args}") - - if args.grayskull_power: - print( - f"{Fore.BLUE}By the power of Grayskull...\n" - f"{Style.BRIGHT}I have the power!" - ) - return - - CLIConfig().stdout = args.stdout - CLIConfig().list_missing_deps = args.list_missing_deps - - print_msg(Style.RESET_ALL) - print_msg(clear_screen()) - - if getattr(args, "pypi_packages", None): - generate_recipes_from_list(args.pypi_packages, args) - elif getattr(args, "cran_packages", None): - generate_r_recipes_from_list(args.cran_packages, args) - - -def generate_recipes_from_list(list_pkgs, args): - for pkg_name in list_pkgs: - logging.debug(f"Starting grayskull for pkg: {pkg_name}") - from_local_sdist = origin_is_local_sdist(pkg_name) - if origin_is_github(pkg_name): - pypi_label = "" - elif from_local_sdist: - pypi_label = " (local)" - else: - pypi_label = " (pypi)" - print_msg( - f"{Fore.GREEN}\n\n" - f"#### Initializing recipe for " - f"{Fore.BLUE}{pkg_name}{pypi_label} {Fore.GREEN}####\n" - ) - if Path(pkg_name).is_file() and (not from_local_sdist): - args.output = pkg_name - try: - recipe, config = create_python_recipe( - pkg_name, - is_strict_cf=args.is_strict_conda_forge, - download=args.download, - url_pypi_metadata=args.url_pypi_metadata, - sections_populate=args.sections_populate, - from_local_sdist=from_local_sdist, - extras_require_test=args.extras_require_test, - github_release_tag=args.github_release_tag, - extras_require_include=tuple(args.extras_require_include), - extras_require_exclude=tuple(args.extras_require_exclude), - extras_require_all=args.extras_require_all, - extras_require_split=args.extras_require_split, - licence_exclude_folders=args.licence_exclude_folders, - ) - except requests.exceptions.HTTPError as err: - print_msg(f"{Fore.RED}Package seems to be missing.\nException: {err}\n\n") - continue - - if args.sections_populate is None or "extra" in args.sections_populate: - add_extra_section(recipe, args.maintainers) - - generate_recipe(recipe, config, args.output) - print_msg( - f"\n{Fore.GREEN}#### Recipe generated on " - f"{os.path.realpath(args.output)} for {pkg_name} ####\n\n" - ) - - if args.is_recursive and config.missing_deps: - generate_recipes_from_list(config.missing_deps, args) - - -def create_python_recipe(pkg_name, sections_populate=None, **kwargs): - config = Configuration(name=pkg_name, **kwargs) - return ( - GrayskullFactory.create_recipe( - "pypi", config, sections_populate=sections_populate - ), - config, - ) - - -def generate_r_recipes_from_list(list_pkgs, args): - cran_label = " (cran)" - for pkg_name in list_pkgs: - logging.debug(f"Starting grayskull for pkg: {pkg_name}") - from_local_sdist = origin_is_local_sdist(pkg_name) - print_msg( - f"{Fore.GREEN}\n\n" - f"#### Initializing recipe for " - f"{Fore.BLUE}{pkg_name}{cran_label} {Fore.GREEN}####\n" - ) - if Path(pkg_name).is_file() and (not from_local_sdist): - args.output = pkg_name - try: - recipe, config = create_r_recipe( - pkg_name, - is_strict_cf=args.is_strict_conda_forge, - download=args.download, - sections_populate=args.sections_populate, - ) - except requests.exceptions.HTTPError as err: - print_msg(f"{Fore.RED}Package seems to be missing.\nException: {err}\n\n") - continue - - if args.sections_populate is None or "extra" in args.sections_populate: - add_extra_section(recipe, args.maintainers) - - generate_recipe(recipe, config, args.output) - print_msg( - f"\n{Fore.GREEN}#### Recipe generated on " - f"{os.path.realpath(args.output)} for {pkg_name} ####\n\n" - ) - - -def create_r_recipe(pkg_name, sections_populate=None, **kwargs): - config = Configuration(name=pkg_name, **kwargs) - return ( - GrayskullFactory.create_recipe( - "cran", config, sections_populate=sections_populate - ), - config, - ) - - -def add_extra_section(recipe, maintainers: Optional[List] = None): - maintainers = maintainers or [get_git_current_user()] - if "extra" in recipe: - recipe["extra"]["recipe-maintainers"] = maintainers - else: - recipe.add_section({"extra": {"recipe-maintainers": maintainers}}) - prefix = f"\n - {Fore.LIGHTMAGENTA_EX}" - print_msg(f"\nMaintainers:{prefix}{prefix.join(maintainers)}") - +from .main import main if __name__ == "__main__": main(sys.argv[1:]) diff --git a/grayskull/main.py b/grayskull/main.py new file mode 100644 index 000000000..fa834c40d --- /dev/null +++ b/grayskull/main.py @@ -0,0 +1,393 @@ +import argparse +import logging +import os +import sys +from pathlib import Path +from typing import List, Optional + +import requests +from colorama import Fore, Style, init +from colorama.ansi import clear_screen + +import grayskull +from grayskull.base.factory import GrayskullFactory +from grayskull.base.github import get_git_current_user +from grayskull.cli import CLIConfig +from grayskull.cli.stdout import print_msg +from grayskull.config import Configuration +from grayskull.utils import generate_recipe, origin_is_github, origin_is_local_sdist + +init(autoreset=True) +logging.basicConfig(format="%(levelname)s:%(message)s") + + +def build_parser(): + + # create the top-level parser + parser = argparse.ArgumentParser(description="Grayskull - Conda recipe generator") + subparsers = parser.add_subparsers(help="sub-command help") + # create parser for cran + cran_parser = subparsers.add_parser("cran", help="Options to generate CRAN recipes") + cran_parser.add_argument( + "cran_packages", nargs="+", help="Specify the CRAN packages name.", default=[] + ) + cran_parser.add_argument( + "--stdout", + dest="stdout", + default=True, + help="Disable or enable stdout, if it is False, Grayskull" + " will disable the prints. Default is True", + ) + cran_parser.add_argument( + "--list-missing-deps", + default=False, + action="store_true", + dest="list_missing_deps", + help="After the execution Grayskull will print all the missing dependencies.", + ) + cran_parser.add_argument( + "--download", + "-d", + dest="download", + action="store_true", + default=False, + help="Download the sdist package and PyPI information in the same folder" + " the recipe is located.", + ) + cran_parser.add_argument( + "--maintainers", + "-m", + dest="maintainers", + nargs="+", + help="List of maintainers which will be added to the recipe.", + ) + cran_parser.add_argument( + "--output", + "-o", + dest="output", + default=".", + help="Path to where the recipe will be created", + ) + cran_parser.add_argument( + "--strict-conda-forge", + default=False, + action="store_true", + dest="is_strict_conda_forge", + help="It will generate the recipes strict for the conda-forge channel.", + ) + cran_parser.add_argument( + "--sections", + "-s", + default=None, + required=False, + choices=( + "package", + "source", + "build", + "requirements", + "test", + "about", + "extra", + ), + nargs="+", + dest="sections_populate", + help="If sections are specified, grayskull will populate just the sections " + "informed.", + ) + # create parser for pypi + pypi_parser = subparsers.add_parser("pypi", help="Options to generate PyPI recipes") + pypi_parser.add_argument( + "pypi_packages", nargs="+", help="Specify the PyPI packages name.", default=[] + ) + pypi_parser.add_argument( + "--download", + "-d", + dest="download", + action="store_true", + default=False, + help="Download the sdist package and PyPI information in the same folder" + " the recipe is located.", + ) + pypi_parser.add_argument( + "--maintainers", + "-m", + dest="maintainers", + nargs="+", + help="List of maintainers which will be added to the recipe.", + ) + parser.add_argument( + "--version", + "-v", + default=False, + action="store_true", + dest="version", + help="Print Grayskull version and exit", + ) + parser.add_argument( + "--heman", + "--shera", + default=False, + action="store_true", + dest="grayskull_power", + help=argparse.SUPPRESS, + ) + pypi_parser.add_argument( + "--output", + "-o", + dest="output", + default=".", + help="Path to where the recipe will be created", + ) + pypi_parser.add_argument( + "--stdout", + dest="stdout", + default=True, + help="Disable or enable stdout, if it is False, Grayskull" + " will disable the prints. Default is True", + ) + pypi_parser.add_argument( + "--list-missing-deps", + default=False, + action="store_true", + dest="list_missing_deps", + help="After the execution Grayskull will print all the missing dependencies.", + ) + pypi_parser.add_argument( + "--strict-conda-forge", + default=False, + action="store_true", + dest="is_strict_conda_forge", + help="It will generate the recipes strict for the conda-forge channel.", + ) + pypi_parser.add_argument( + "--pypi-url", + default="https://pypi.org/pypi/", + dest="url_pypi_metadata", + help="Pypi url server", + ) + pypi_parser.add_argument( + "--recursive", + "-r", + default=False, + action="store_true", + dest="is_recursive", + help="Recursively run grayskull on missing dependencies.", + ) + pypi_parser.add_argument( + "--sections", + "-s", + default=None, + required=False, + choices=( + "package", + "source", + "build", + "requirements", + "test", + "about", + "extra", + ), + nargs="+", + dest="sections_populate", + help="If sections are specified, grayskull will populate just the sections " + "informed.", + ) + pypi_parser.add_argument( + "--extras-require-test", + default=None, + dest="extras_require_test", + help="Extra requirements to run tests.", + ) + pypi_parser.add_argument( + "--tag", + "-t", + default=None, + dest="github_release_tag", + help="If tag is specified, grayskull will build from release tag", + ) + pypi_parser.add_argument( + "--extras-require-all", + default=False, + action="store_true", + dest="extras_require_all", + help="Include all extra requirements.", + ) + pypi_parser.add_argument( + "--extras-require-include", + default=tuple(), + type=str, + nargs="*", + dest="extras_require_include", + help="Include these extra requirements.", + ) + pypi_parser.add_argument( + "--extras-require-exclude", + default=tuple(), + type=str, + nargs="*", + dest="extras_require_exclude", + help="Exclude these extra requirements (overrides include).", + ) + pypi_parser.add_argument( + "--extras-require-split", + default=False, + action="store_true", + dest="extras_require_split", + help="Create a separate conda package for each extra requirements." + " Ignored when no extra requirements are selected.", + ) + pypi_parser.add_argument( + "--licence-exclude-folders", + default=tuple(), + nargs="*", + dest="licence_exclude_folders", + help="Exclude folders when searching for licence.", + ) + + return parser + + +def main(args=None): + if not args: + args = sys.argv[1:] or ["--help"] + + parser = build_parser() + + args = parser.parse_args(args) + + if args.version: + print(grayskull.__version__) + return + + logging.debug(f"All arguments received: args: {args}") + + if args.grayskull_power: + print( + f"{Fore.BLUE}By the power of Grayskull...\n" + f"{Style.BRIGHT}I have the power!" + ) + return + + CLIConfig().stdout = args.stdout + CLIConfig().list_missing_deps = args.list_missing_deps + + print_msg(Style.RESET_ALL) + print_msg(clear_screen()) + + if getattr(args, "pypi_packages", None): + generate_recipes_from_list(args.pypi_packages, args) + elif getattr(args, "cran_packages", None): + generate_r_recipes_from_list(args.cran_packages, args) + + +def generate_recipes_from_list(list_pkgs, args): + for pkg_name in list_pkgs: + logging.debug(f"Starting grayskull for pkg: {pkg_name}") + from_local_sdist = origin_is_local_sdist(pkg_name) + if origin_is_github(pkg_name): + pypi_label = "" + elif from_local_sdist: + pypi_label = " (local)" + else: + pypi_label = " (pypi)" + print_msg( + f"{Fore.GREEN}\n\n" + f"#### Initializing recipe for " + f"{Fore.BLUE}{pkg_name}{pypi_label} {Fore.GREEN}####\n" + ) + if Path(pkg_name).is_file() and (not from_local_sdist): + args.output = pkg_name + try: + recipe, config = create_python_recipe( + pkg_name, + is_strict_cf=args.is_strict_conda_forge, + download=args.download, + url_pypi_metadata=args.url_pypi_metadata, + sections_populate=args.sections_populate, + from_local_sdist=from_local_sdist, + extras_require_test=args.extras_require_test, + github_release_tag=args.github_release_tag, + extras_require_include=tuple(args.extras_require_include), + extras_require_exclude=tuple(args.extras_require_exclude), + extras_require_all=args.extras_require_all, + extras_require_split=args.extras_require_split, + licence_exclude_folders=args.licence_exclude_folders, + ) + except requests.exceptions.HTTPError as err: + print_msg(f"{Fore.RED}Package seems to be missing.\nException: {err}\n\n") + continue + + if args.sections_populate is None or "extra" in args.sections_populate: + add_extra_section(recipe, args.maintainers) + + generate_recipe(recipe, config, args.output) + print_msg( + f"\n{Fore.GREEN}#### Recipe generated on " + f"{os.path.realpath(args.output)} for {pkg_name} ####\n\n" + ) + + if args.is_recursive and config.missing_deps: + generate_recipes_from_list(config.missing_deps, args) + + +def create_python_recipe(pkg_name, sections_populate=None, **kwargs): + config = Configuration(name=pkg_name, **kwargs) + return ( + GrayskullFactory.create_recipe( + "pypi", config, sections_populate=sections_populate + ), + config, + ) + + +def generate_r_recipes_from_list(list_pkgs, args): + cran_label = " (cran)" + for pkg_name in list_pkgs: + logging.debug(f"Starting grayskull for pkg: {pkg_name}") + from_local_sdist = origin_is_local_sdist(pkg_name) + print_msg( + f"{Fore.GREEN}\n\n" + f"#### Initializing recipe for " + f"{Fore.BLUE}{pkg_name}{cran_label} {Fore.GREEN}####\n" + ) + if Path(pkg_name).is_file() and (not from_local_sdist): + args.output = pkg_name + try: + recipe, config = create_r_recipe( + pkg_name, + is_strict_cf=args.is_strict_conda_forge, + download=args.download, + sections_populate=args.sections_populate, + ) + except requests.exceptions.HTTPError as err: + print_msg(f"{Fore.RED}Package seems to be missing.\nException: {err}\n\n") + continue + + if args.sections_populate is None or "extra" in args.sections_populate: + add_extra_section(recipe, args.maintainers) + + generate_recipe(recipe, config, args.output) + print_msg( + f"\n{Fore.GREEN}#### Recipe generated on " + f"{os.path.realpath(args.output)} for {pkg_name} ####\n\n" + ) + + +def create_r_recipe(pkg_name, sections_populate=None, **kwargs): + config = Configuration(name=pkg_name, **kwargs) + return ( + GrayskullFactory.create_recipe( + "cran", config, sections_populate=sections_populate + ), + config, + ) + + +def add_extra_section(recipe, maintainers: Optional[List] = None): + maintainers = maintainers or [get_git_current_user()] + if "extra" in recipe: + recipe["extra"]["recipe-maintainers"] = maintainers + else: + recipe.add_section({"extra": {"recipe-maintainers": maintainers}}) + prefix = f"\n - {Fore.LIGHTMAGENTA_EX}" + print_msg(f"\nMaintainers:{prefix}{prefix.join(maintainers)}") diff --git a/pyproject.toml b/pyproject.toml index 9742c0115..c00f6baf4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,19 +1,16 @@ [build-system] -requires = [ - "setuptools >=61", - "setuptools_scm[toml]>=6.2", -] +requires = ["setuptools >=61", "setuptools_scm[toml]>=6.2"] build-backend = "setuptools.build_meta" [project] name = "grayskull" authors = [ - {name = "Marcelo Duarte Trevisani", email = "marceloduartetrevisani@gmail.com"}, + { name = "Marcelo Duarte Trevisani", email = "marceloduartetrevisani@gmail.com" }, ] description = "Project to generate recipes for conda packages" readme = "README.md" keywords = ["conda"] -license = {text = "Apache-2.0"} +license = { text = "Apache-2.0" } dynamic = ["version"] requires-python = ">=3.8" dependencies = [ @@ -44,6 +41,14 @@ testing = [ "setuptools-scm", ] +docs = [ + "furo", + "sphinx", + "sphinx-argparse", + "myst-parser", + "mdit-py-plugins>=0.3.0", +] + [project.scripts] grayskull = "grayskull.__main__:main" greyskull = "grayskull.__main__:main" @@ -60,8 +65,8 @@ include = ["grayskull", "grayskull.*"] write_to = "grayskull/_version.py" [tool.black] -target-version=["py310"] -exclude=''' +target-version = ["py310"] +exclude = ''' /( \.eggs | \.git From 60ef8eb07e06a9452aefdec44e6235d9ffcd3150 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 27 Mar 2023 17:51:42 +0000 Subject: [PATCH 02/11] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- grayskull/main.py | 1 - 1 file changed, 1 deletion(-) diff --git a/grayskull/main.py b/grayskull/main.py index fa834c40d..2db4ab727 100644 --- a/grayskull/main.py +++ b/grayskull/main.py @@ -22,7 +22,6 @@ def build_parser(): - # create the top-level parser parser = argparse.ArgumentParser(description="Grayskull - Conda recipe generator") subparsers = parser.add_subparsers(help="sub-command help") From 66e4b725284945f227fd5fe37abc9bfbadc86010 Mon Sep 17 00:00:00 2001 From: Daniel Holth Date: Mon, 27 Mar 2023 13:54:36 -0400 Subject: [PATCH 03/11] cd docs --- .github/workflows/sphinx.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/sphinx.yml b/.github/workflows/sphinx.yml index 717b3bcba..cb66b20de 100644 --- a/.github/workflows/sphinx.yml +++ b/.github/workflows/sphinx.yml @@ -24,6 +24,7 @@ jobs: run: | pip install -e .[docs] pip install -r docs/requirements.txt # redundant? + cd docs make html - name: Upload artifact uses: actions/upload-pages-artifact@v1 From 69885f9d7a917cfb157bef81aca8152b851f032b Mon Sep 17 00:00:00 2001 From: Daniel Holth Date: Mon, 27 Mar 2023 13:56:49 -0400 Subject: [PATCH 04/11] change artifact path --- .github/workflows/sphinx.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/sphinx.yml b/.github/workflows/sphinx.yml index cb66b20de..7f3b270a9 100644 --- a/.github/workflows/sphinx.yml +++ b/.github/workflows/sphinx.yml @@ -30,7 +30,7 @@ jobs: uses: actions/upload-pages-artifact@v1 with: # Upload entire repository - path: 'build/html' + path: 'docs/build/html' pages: From 7b0e20a7ce5260fea2b26e278450e7c297ec00fc Mon Sep 17 00:00:00 2001 From: Daniel Holth Date: Mon, 27 Mar 2023 15:01:06 -0400 Subject: [PATCH 05/11] rename module in tests --- tests/cli/test_cli_recipes.py | 2 +- tests/test_github_recipes.py | 2 +- tests/test_py_base.py | 2 +- tests/test_pypi.py | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/cli/test_cli_recipes.py b/tests/cli/test_cli_recipes.py index 9e7b7c879..4c8602213 100644 --- a/tests/cli/test_cli_recipes.py +++ b/tests/cli/test_cli_recipes.py @@ -1,6 +1,6 @@ from souschef.recipe import Recipe -from grayskull.__main__ import main +from grayskull.main import main def test_loop_deps_nipy_and_maintainers(tmpdir, mocker): diff --git a/tests/test_github_recipes.py b/tests/test_github_recipes.py index f3ee8e08d..788f61d92 100644 --- a/tests/test_github_recipes.py +++ b/tests/test_github_recipes.py @@ -1,7 +1,7 @@ import pytest from souschef.jinja_expression import get_global_jinja_var -from grayskull.__main__ import create_python_recipe +from grayskull.main import create_python_recipe from grayskull.strategy.pypi import adjust_source_url_to_include_placeholders diff --git a/tests/test_py_base.py b/tests/test_py_base.py index e3e62dd2a..64a5b03c2 100644 --- a/tests/test_py_base.py +++ b/tests/test_py_base.py @@ -1,6 +1,6 @@ from pathlib import Path -from grayskull.__main__ import create_python_recipe +from grayskull.main import create_python_recipe from grayskull.config import Configuration from grayskull.strategy.py_base import ( clean_deps_for_conda_forge, diff --git a/tests/test_pypi.py b/tests/test_pypi.py index 4253e0129..38277afd6 100644 --- a/tests/test_pypi.py +++ b/tests/test_pypi.py @@ -8,7 +8,7 @@ from colorama import Fore, Style from souschef.recipe import Recipe -from grayskull.__main__ import create_python_recipe +from grayskull.main import create_python_recipe from grayskull.base.factory import GrayskullFactory from grayskull.base.pkg_info import normalize_pkg_name from grayskull.cli import CLIConfig From 3f9a8f1751c9ce5e92e4ce74702bb5ad6137f7db Mon Sep 17 00:00:00 2001 From: Daniel Holth Date: Mon, 27 Mar 2023 15:18:02 -0400 Subject: [PATCH 06/11] convert to markdown --- docs/source/developer_guide.md | 7 ++++++ docs/source/developer_guide.rst | 6 ------ docs/source/index.md | 38 +++++++++++++++++++++++++++++++++ docs/source/index.rst | 37 -------------------------------- docs/source/user_guide.md | 25 ++++++++++++++++++++++ docs/source/user_guide.rst | 30 -------------------------- 6 files changed, 70 insertions(+), 73 deletions(-) create mode 100644 docs/source/developer_guide.md delete mode 100644 docs/source/developer_guide.rst create mode 100644 docs/source/index.md delete mode 100644 docs/source/index.rst create mode 100644 docs/source/user_guide.md delete mode 100644 docs/source/user_guide.rst diff --git a/docs/source/developer_guide.md b/docs/source/developer_guide.md new file mode 100644 index 000000000..ad9a690f4 --- /dev/null +++ b/docs/source/developer_guide.md @@ -0,0 +1,7 @@ +# Developer Guide + +The Grayskull project is under active development. + +We courage community members to contribute to this development. + +The Grayskull source code can be found [on GitHub](https://github.com/conda/grayskull/tree/main/grayskull). diff --git a/docs/source/developer_guide.rst b/docs/source/developer_guide.rst deleted file mode 100644 index 7affd0958..000000000 --- a/docs/source/developer_guide.rst +++ /dev/null @@ -1,6 +0,0 @@ -Developer Guide -=============== - -| The Grayskull project is under active development. -| We courage community members to contribute to this development. -| The Grayskull source code can be found `here `_. diff --git a/docs/source/index.md b/docs/source/index.md new file mode 100644 index 000000000..eb0764226 --- /dev/null +++ b/docs/source/index.md @@ -0,0 +1,38 @@ +% Grayskull documentation master file, created by +% sphinx-quickstart on Tue Feb 15 20:08:45 2022. +% You can adapt this file completely to your liking, but it should at least +% contain the root `toctree` directive. + +# Grayskull Documentation + +**Grayskull** + + is an automatic conda recipe generator. + +The main goal of this project is to generate concise recipes for [conda-forge](https://github.com/conda-forge). + +Presently Grayskull can generate recipes for Python packages available on PyPI and also those not published on PyPI but available as GitHub repositories. + +Future versions of Grayskull will support recipe generation for packages of other repositories such as CRAN and Conan etc.. + +Check out the {doc}`user_guide` section for further information, including how +to {ref}`install ` Grayskull. + +```{toctree} +:caption: 'Contents:' +:maxdepth: 1 + +user_guide +cli +developer_guide +``` + +```{note} +This project is under active development. +``` + +# Indices and tables + +- {ref}`genindex` +- {ref}`modindex` +- {ref}`search` diff --git a/docs/source/index.rst b/docs/source/index.rst deleted file mode 100644 index bc15fb2ec..000000000 --- a/docs/source/index.rst +++ /dev/null @@ -1,37 +0,0 @@ -.. Grayskull documentation master file, created by - sphinx-quickstart on Tue Feb 15 20:08:45 2022. - You can adapt this file completely to your liking, but it should at least - contain the root `toctree` directive. - -Grayskull Documentation -======================== - -| **Grayskull** is an automatic conda recipe generator. -| The main goal of this project is to generate concise recipes for `conda-forge `_. - -| Presently Grayskull can generate recipes for Python packages available on PyPI and also those not published on PyPI but available as GitHub repositories. -| Future versions of Grayskull will support recipe generation for packages of other repositories such as CRAN and Conan etc.. - -| Check out the :doc:`user_guide` section for further information, including how to :ref:`install ` Grayskull. - - -.. toctree:: - :maxdepth: 1 - :caption: Contents: - - user_guide - cli - developer_guide - - - -.. note:: - - This project is under active development. - -Indices and tables -================== - -* :ref:`genindex` -* :ref:`modindex` -* :ref:`search` diff --git a/docs/source/user_guide.md b/docs/source/user_guide.md new file mode 100644 index 000000000..d49531654 --- /dev/null +++ b/docs/source/user_guide.md @@ -0,0 +1,25 @@ +# User Guide + +(installation)= + +## Installation + +Grayskull can be installed with `pip`: + +``` +pip install grayskull +``` + +or with `conda`, using the `conda-forge` channel: + +``` +conda install -c conda-forge grayskull +``` + +It is also possible to clone the Grayskull repository and install it using `pip`: + +``` +git clone https://github.com/conda/grayskull.git +cd grayskull +pip install -e . +``` diff --git a/docs/source/user_guide.rst b/docs/source/user_guide.rst deleted file mode 100644 index b7991bc0b..000000000 --- a/docs/source/user_guide.rst +++ /dev/null @@ -1,30 +0,0 @@ -User Guide -========== - -.. _installation: - -Installation ------------- - -| Grayskull can be installed with ``pip``: - -:: - - pip install grayskull - -| or with ``conda``, using the ``conda-forge`` channel: - -:: - - conda install -c conda-forge grayskull - -It is also possible to clone the Grayskull repository and install it using ``pip``: - -:: - - git clone https://github.com/conda/grayskull.git - cd grayskull - pip install -e . - - - From c29df405c8965e82d48be6dea1bb27df68e691ba Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 27 Mar 2023 20:12:32 +0000 Subject: [PATCH 07/11] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- grayskull/__main__.py | 1 + tests/test_py_base.py | 2 +- tests/test_pypi.py | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/grayskull/__main__.py b/grayskull/__main__.py index cc4800ce9..e101a3180 100644 --- a/grayskull/__main__.py +++ b/grayskull/__main__.py @@ -1,4 +1,5 @@ import sys + from .main import main if __name__ == "__main__": diff --git a/tests/test_py_base.py b/tests/test_py_base.py index 64a5b03c2..8e711162e 100644 --- a/tests/test_py_base.py +++ b/tests/test_py_base.py @@ -1,7 +1,7 @@ from pathlib import Path -from grayskull.main import create_python_recipe from grayskull.config import Configuration +from grayskull.main import create_python_recipe from grayskull.strategy.py_base import ( clean_deps_for_conda_forge, ensure_pep440, diff --git a/tests/test_pypi.py b/tests/test_pypi.py index 38277afd6..b3178fe14 100644 --- a/tests/test_pypi.py +++ b/tests/test_pypi.py @@ -8,12 +8,12 @@ from colorama import Fore, Style from souschef.recipe import Recipe -from grayskull.main import create_python_recipe from grayskull.base.factory import GrayskullFactory from grayskull.base.pkg_info import normalize_pkg_name from grayskull.cli import CLIConfig from grayskull.cli.parser import parse_pkg_name_version from grayskull.config import Configuration +from grayskull.main import create_python_recipe from grayskull.strategy.py_base import ( clean_deps_for_conda_forge, generic_py_ver_to, From e44c1d94ff97975dd8069205da2341723d2d2814 Mon Sep 17 00:00:00 2001 From: Daniel Holth Date: Mon, 27 Mar 2023 16:28:12 -0400 Subject: [PATCH 08/11] adjust import --- tests/test_poetry.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_poetry.py b/tests/test_poetry.py index 429128d10..163945a9c 100644 --- a/tests/test_poetry.py +++ b/tests/test_poetry.py @@ -5,7 +5,7 @@ import pytest -from grayskull.__main__ import generate_recipes_from_list, init_parser +from grayskull.main import generate_recipes_from_list, init_parser from grayskull.strategy.py_toml import ( InvalidVersion, add_poetry_metadata, From 7d49dd4e9664906c1b737fbb08bd47a0b30d01f1 Mon Sep 17 00:00:00 2001 From: Daniel Holth Date: Mon, 27 Mar 2023 16:57:41 -0400 Subject: [PATCH 09/11] additonal __main__ rename --- pyproject.toml | 8 ++++---- tests/cli/test_cli_cmds.py | 6 +++--- tests/cli/test_cli_recipes.py | 2 +- tests/test_pypi.py | 2 +- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 06e370982..e8ed563e1 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -51,10 +51,10 @@ docs = [ ] [project.scripts] -grayskull = "grayskull.__main__:main" -greyskull = "grayskull.__main__:main" -conda-grayskull = "grayskull.__main__:main" -conda-greyskull = "grayskull.__main__:main" +grayskull = "grayskull.main:main" +greyskull = "grayskull.main:main" +conda-grayskull = "grayskull.main:main" +conda-greyskull = "grayskull.main:main" [project.urls] Source = "https://github.com/conda/grayskull" diff --git a/tests/cli/test_cli_cmds.py b/tests/cli/test_cli_cmds.py index 16bdbbd23..045b53c8d 100644 --- a/tests/cli/test_cli_cmds.py +++ b/tests/cli/test_cli_cmds.py @@ -64,11 +64,11 @@ def test_license_discovery(tmpdir): def test_change_pypi_url(mocker): - mocker.patch("grayskull.__main__.generate_recipe", return_value=None) + mocker.patch("grayskull.main.generate_recipe", return_value=None) mocker.patch( - "grayskull.__main__.create_python_recipe", return_value=({"extra": {}}, None) + "grayskull.main.create_python_recipe", return_value=({"extra": {}}, None) ) - mocker.patch("grayskull.__main__.add_extra_section", return_value=None) + mocker.patch("grayskull.main.add_extra_section", return_value=None) spy = mocker.spy(cli, "create_python_recipe") cli.main(["pypi", "pytest=5.3.2", "--pypi-url=http://url_pypi.com/abc"]) diff --git a/tests/cli/test_cli_recipes.py b/tests/cli/test_cli_recipes.py index 4c8602213..43e4921c7 100644 --- a/tests/cli/test_cli_recipes.py +++ b/tests/cli/test_cli_recipes.py @@ -4,7 +4,7 @@ def test_loop_deps_nipy_and_maintainers(tmpdir, mocker): - mocker.patch("grayskull.__main__.get_git_current_user", return_value="GIT_USER") + mocker.patch("grayskull.main.get_git_current_user", return_value="GIT_USER") out_folder = tmpdir.mkdir("out") main(["pypi", "nipy=0.4.2", "-o", str(out_folder), "--download"]) nipy_folder = out_folder / "nipy" diff --git a/tests/test_pypi.py b/tests/test_pypi.py index b3178fe14..e05ad7e58 100644 --- a/tests/test_pypi.py +++ b/tests/test_pypi.py @@ -884,7 +884,7 @@ def test_ipytest_recipe_license(): def test_get_test_entry_points(): - assert get_test_entry_points("grayskull = grayskull.__main__:main") == [ + assert get_test_entry_points("grayskull = grayskull.main:main") == [ "grayskull --help" ] assert get_test_entry_points( From 58771e09606d11a14231094390b223c49b2eee47 Mon Sep 17 00:00:00 2001 From: Daniel Holth Date: Tue, 28 Mar 2023 09:12:41 -0400 Subject: [PATCH 10/11] Apply suggestions from code review Co-authored-by: Mahe Iram Khan <65779580+ForgottenProgramme@users.noreply.github.com> --- docs/source/index.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/source/index.md b/docs/source/index.md index eb0764226..f3262bed2 100644 --- a/docs/source/index.md +++ b/docs/source/index.md @@ -11,9 +11,10 @@ The main goal of this project is to generate concise recipes for [conda-forge](https://github.com/conda-forge). -Presently Grayskull can generate recipes for Python packages available on PyPI and also those not published on PyPI but available as GitHub repositories. +Presently Grayskull can generate recipes for Python packages available on PyPI and also those not published on PyPI but available as GitHub repositories. +Grayskull can also generate recipes for R packages published on CRAN. -Future versions of Grayskull will support recipe generation for packages of other repositories such as CRAN and Conan etc.. +Future versions of Grayskull will support recipe generation for packages of other repositories such as Conan, CPAN etc.. Check out the {doc}`user_guide` section for further information, including how to {ref}`install ` Grayskull. From 2d9ee39e5fc3c26b5b86e6c3e1c420c7c363b26a Mon Sep 17 00:00:00 2001 From: Daniel Holth Date: Tue, 28 Mar 2023 09:38:19 -0400 Subject: [PATCH 11/11] additional __main__ --- tests/cli/test_cli_cmds.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/cli/test_cli_cmds.py b/tests/cli/test_cli_cmds.py index 045b53c8d..009c64af0 100644 --- a/tests/cli/test_cli_cmds.py +++ b/tests/cli/test_cli_cmds.py @@ -5,7 +5,7 @@ from souschef.recipe import Recipe import grayskull -from grayskull import __main__ as cli +from grayskull import main as cli from grayskull.base.factory import GrayskullFactory from grayskull.config import Configuration