diff --git a/packages/griffe/LICENSE b/packages/griffe/LICENSE new file mode 100644 index 00000000..8becbc45 --- /dev/null +++ b/packages/griffe/LICENSE @@ -0,0 +1,15 @@ +ISC License + +Copyright (c) 2021, Timothée Mazzucotelli + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. diff --git a/packages/griffe/README.md b/packages/griffe/README.md new file mode 100644 index 00000000..7fbc0b5b --- /dev/null +++ b/packages/griffe/README.md @@ -0,0 +1,115 @@ +# Griffe + +[![ci](https://github.com/mkdocstrings/griffe/workflows/ci/badge.svg)](https://github.com/mkdocstrings/griffe/actions?query=workflow%3Aci) +[![documentation](https://img.shields.io/badge/docs-mkdocs-708FCC.svg?style=flat)](https://mkdocstrings.github.io/griffe/) +[![pypi version](https://img.shields.io/pypi/v/griffe.svg)](https://pypi.org/project/griffe/) +[![gitter](https://img.shields.io/badge/matrix-chat-4db798.svg?style=flat)](https://app.gitter.im/#/room/#mkdocstrings_griffe:gitter.im) +[![radicle](https://img.shields.io/badge/rad-clone-6666FF.svg?style=flat)](https://app.radicle.at/nodes/seed.radicle.at/rad:z4M5XTPDD4Wh1sm8iPCenF85J3z8Z) + +Griffe logo, created by François Rozet + +Signatures for entire Python programs. Extract the structure, the frame, the skeleton of your project, to generate API documentation or find breaking changes in your API. + +Griffe, pronounced "grif" (`/ɡʁif/`), is a french word that means "claw", +but also "signature" in a familiar way. "On reconnaît bien là sa griffe." + +- [User guide](https://mkdocstrings.github.io/griffe/guide/users/) +- [Contributor guide](https://mkdocstrings.github.io/griffe/guide/contributors/) +- [API reference](https://mkdocstrings.github.io/griffe/reference/api/) + +## Installation + +```bash +pip install griffe +``` + +With [`uv`](https://docs.astral.sh/uv/): + +```bash +uv tool install griffe +``` + +## Usage + +### Dump JSON-serialized API + +**On the command line**, pass the names of packages to the `griffe dump` command: + +```console +$ griffe dump httpx fastapi +{ + "httpx": { + "name": "httpx", + ... + }, + "fastapi": { + "name": "fastapi", + ... + } +} +``` + +See the [Serializing chapter](https://mkdocstrings.github.io/griffe/guide/users/serializing/) for more examples. + +### Check for API breaking changes + +Pass a relative path to the `griffe check` command: + +```console +$ griffe check mypackage --verbose +mypackage/mymodule.py:10: MyClass.mymethod(myparam): +Parameter kind was changed: + Old: positional or keyword + New: keyword-only +``` + +For `src` layouts: + +```console +$ griffe check --search src mypackage --verbose +src/mypackage/mymodule.py:10: MyClass.mymethod(myparam): +Parameter kind was changed: + Old: positional or keyword + New: keyword-only +``` + +It's also possible to directly **check packages from PyPI.org** +(or other indexes configured through `PIP_INDEX_URL`). +This feature is [available to sponsors only](https://mkdocstrings.github.io/griffe/insiders/) +and requires that you install Griffe with the `pypi` extra: + +```bash +pip install griffe[pypi] +``` + +The command syntax is: + +```bash +griffe check package_name -b project-name==2.0 -a project-name==1.0 +``` + +See the [Checking chapter](https://mkdocstrings.github.io/griffe/guide/users/checking/) for more examples. + +### Load and navigate data with Python + +**With Python**, loading a package: + +```python +import griffe + +fastapi = griffe.load("fastapi") +``` + +Finding breaking changes: + +```python +import griffe + +previous = griffe.load_git("mypackage", ref="0.2.0") +current = griffe.load("mypackage") + +for breakage in griffe.find_breaking_changes(previous, current): + ... +``` + +See the [Loading chapter](https://mkdocstrings.github.io/griffe/guide/users/loading/) for more examples. diff --git a/src/griffe/_internal/py.typed b/packages/griffe/pyproject.toml similarity index 100% rename from src/griffe/_internal/py.typed rename to packages/griffe/pyproject.toml diff --git a/packages/griffe/src/griffe/__init__.py b/packages/griffe/src/griffe/__init__.py new file mode 100644 index 00000000..78129ca5 --- /dev/null +++ b/packages/griffe/src/griffe/__init__.py @@ -0,0 +1,166 @@ +# This top-level module imports all public names from the package, +# and exposes them as public objects. We have tests to make sure +# no object is forgotten in this list. + +"""Griffe package. + +Signatures for entire Python programs. +Extract the structure, the frame, the skeleton of your project, +to generate API documentation or find breaking changes in your API. + +The entirety of the public API is exposed here, in the top-level `griffe` module. + +All messages written to standard output or error are logged using the `logging` module. +Our logger's name is set to `"griffe"` and is public (you can rely on it). +You can obtain the logger from the standard `logging` module: `logging.getLogger("griffe")`. +Actual logging messages are not part of the public API (they might change without notice). + +Raised exceptions throughout the package are part of the public API (you can rely on them). +Their actual messages are not part of the public API (they might change without notice). + +The following paragraphs will help you discover the package's content. + +## CLI entrypoints + +Griffe provides a command-line interface (CLI) to interact with the package. The CLI entrypoints can be called from Python code. + +- [`griffe.main`][]: Run the main program. +- [`griffe.check`][]: Check for API breaking changes in two versions of the same package. +- [`griffe.dump`][]: Load packages data and dump it as JSON. + +## Loaders + +To load API data, Griffe provides several high-level functions. + +- [`griffe.load`][]: Load and return a Griffe object. +- [`griffe.load_git`][]: Load and return a module from a specific Git reference. +- [`griffe.load_pypi`][]: Load and return a module from a specific package version downloaded using pip. + +## Models + +The data loaded by Griffe is represented by several classes. + +- [`griffe.Module`][]: The class representing a Python module. +- [`griffe.Class`][]: The class representing a Python class. +- [`griffe.Function`][]: The class representing a Python function or method. +- [`griffe.Attribute`][]: The class representing a Python attribute. +- [`griffe.Alias`][]: This class represents an alias, or indirection, to an object declared in another module. + +Additional classes are available to represent other concepts. + +- [`griffe.Decorator`][]: This class represents a decorator. +- [`griffe.Parameters`][]: This class is a container for parameters. +- [`griffe.Parameter`][]: This class represent a function parameter. + +## Agents + +Griffe is able to analyze code both statically and dynamically, using the following "agents". +However most of the time you will only need to use the loaders above. + +- [`griffe.visit`][]: Parse and visit a module file. +- [`griffe.inspect`][]: Inspect a module. + +## Serializers + +Griffe can serizalize data to dictionary and JSON. + +- [`griffe.Object.as_json`][griffe.Object.as_json] +- [`griffe.Object.from_json`][griffe.Object.from_json] +- [`griffe.JSONEncoder`][]: JSON encoder for Griffe objects. +- [`griffe.json_decoder`][]: JSON decoder for Griffe objects. + +## API checks + +Griffe can compare two versions of the same package to find breaking changes. + +- [`griffe.find_breaking_changes`][]: Find breaking changes between two versions of the same API. +- [`griffe.Breakage`][]: Breakage classes can explain what broke from a version to another. + +## Extensions + +Griffe supports extensions. You can create your own extension by subclassing the `griffe.Extension` class. + +- [`griffe.load_extensions`][]: Load configured extensions. +- [`griffe.Extension`][]: Base class for Griffe extensions. + +## Docstrings + +Griffe can parse docstrings into structured data. + +Main class: + +- [`griffe.Docstring`][]: This class represents docstrings. + +Docstring section and element classes all start with `Docstring`. + +Docstring parsers: + +- [`griffe.parse`][]: Parse the docstring. +- [`griffe.parse_auto`][]: Parse a docstring by automatically detecting the style it uses. +- [`griffe.parse_google`][]: Parse a Google-style docstring. +- [`griffe.parse_numpy`][]: Parse a Numpydoc-style docstring. +- [`griffe.parse_sphinx`][]: Parse a Sphinx-style docstring. + +## Exceptions + +Griffe uses several exceptions to signal errors. + +- [`griffe.GriffeError`][]: The base exception for all Griffe errors. +- [`griffe.LoadingError`][]: Exception for loading errors. +- [`griffe.NameResolutionError`][]: Exception for names that cannot be resolved in a object scope. +- [`griffe.UnhandledEditableModuleError`][]: Exception for unhandled editables modules, when searching modules. +- [`griffe.UnimportableModuleError`][]: Exception for modules that cannot be imported. +- [`griffe.AliasResolutionError`][]: Exception for aliases that cannot be resolved. +- [`griffe.CyclicAliasError`][]: Exception raised when a cycle is detected in aliases. +- [`griffe.LastNodeError`][]: Exception raised when trying to access a next or previous node. +- [`griffe.RootNodeError`][]: Exception raised when trying to use siblings properties on a root node. +- [`griffe.BuiltinModuleError`][]: Exception raised when trying to access the filepath of a builtin module. +- [`griffe.ExtensionError`][]: Base class for errors raised by extensions. +- [`griffe.ExtensionNotLoadedError`][]: Exception raised when an extension could not be loaded. +- [`griffe.GitError`][]: Exception raised for errors related to Git. + +# Expressions + +Griffe stores snippets of code (attribute values, decorators, base class, type annotations) as expressions. +Expressions are basically abstract syntax trees (AST) with a few differences compared to the nodes returned by [`ast`][]. +Griffe provides a few helpers to extract expressions from regular AST nodes. + +- [`griffe.get_annotation`][]: Get a type annotation as expression. +- [`griffe.get_base_class`][]: Get a base class as expression. +- [`griffe.get_condition`][]: Get a condition as expression. +- [`griffe.get_expression`][]: Get an expression from an AST node. +- [`griffe.safe_get_annotation`][]: Get a type annotation as expression, safely (returns `None` on error). +- [`griffe.safe_get_base_class`][]: Get a base class as expression, safely (returns `None` on error). +- [`griffe.safe_get_condition`][]: Get a condition as expression, safely (returns `None` on error). +- [`griffe.safe_get_expression`][]: Get an expression from an AST node, safely (returns `None` on error). + +The base class for expressions. + +- [`griffe.Expr`][] + +Expression classes all start with `Expr`. + +# Loggers + +If you want to log messages from extensions, get a logger with `get_logger`. +The `logger` attribute is used by Griffe itself. You can use it to temporarily disable Griffe logging. + +- [`griffe.logger`][]: Our global logger, used throughout the library. +- [`griffe.get_logger`][]: Create and return a new logger instance. + +# Helpers + +To test your Griffe extensions, or to load API data from code in memory, Griffe provides the following helpers. + +- [`griffe.temporary_pyfile`][]: Create a Python file containing the given code in a temporary directory. +- [`griffe.temporary_pypackage`][]: Create a package containing the given modules in a temporary directory. +- [`griffe.temporary_visited_module`][]: Create and visit a temporary module with the given code. +- [`griffe.temporary_visited_package`][]: Create and visit a temporary package. +- [`griffe.temporary_inspected_module`][]: Create and inspect a temporary module with the given code. +- [`griffe.temporary_inspected_package`][]: Create and inspect a temporary package. +""" + +from __future__ import annotations + +from griffelib import * +from griffelib import __all__ diff --git a/src/griffe/__main__.py b/packages/griffe/src/griffe/__main__.py similarity index 100% rename from src/griffe/__main__.py rename to packages/griffe/src/griffe/__main__.py diff --git a/packages/griffe/src/griffe/_internal/cli.py b/packages/griffe/src/griffe/_internal/cli.py new file mode 100644 index 00000000..f28e4e68 --- /dev/null +++ b/packages/griffe/src/griffe/_internal/cli.py @@ -0,0 +1,571 @@ +# This module contains all CLI-related things. +# Why does this file exist, and why not put this in `__main__`? +# +# We might be tempted to import things from `__main__` later, +# but that will cause problems; the code will get executed twice: +# +# - When we run `python -m griffe`, Python will execute +# `__main__.py` as a script. That means there won't be any +# `griffe.__main__` in `sys.modules`. +# - When you import `__main__` it will get executed again (as a module) because +# there's no `griffe.__main__` in `sys.modules`. + +from __future__ import annotations + +import argparse +import json +import logging +import os +import sys +from datetime import datetime, timezone +from pathlib import Path +from typing import IO, TYPE_CHECKING, Any, Callable + +import colorama +from griffelib._internal import debug +from griffelib._internal.diff import find_breaking_changes +from griffelib._internal.encoders import JSONEncoder +from griffelib._internal.enumerations import ExplanationStyle, Parser +from griffelib._internal.exceptions import ExtensionError, GitError +from griffelib._internal.extensions.base import load_extensions +from griffelib._internal.git import _get_latest_tag, _get_repo_root +from griffelib._internal.loader import GriffeLoader, load, load_git +from griffelib._internal.logger import logger + +if TYPE_CHECKING: + from collections.abc import Sequence + + from griffelib._internal.docstrings.parsers import DocstringOptions, DocstringStyle + from griffelib._internal.extensions.base import Extension, Extensions + + +DEFAULT_LOG_LEVEL = os.getenv("GRIFFE_LOG_LEVEL", "INFO").upper() +"""The default log level for the CLI. + +This can be overridden by the `GRIFFE_LOG_LEVEL` environment variable. +""" + + +class _DebugInfo(argparse.Action): + def __init__(self, nargs: int | str | None = 0, **kwargs: Any) -> None: + super().__init__(nargs=nargs, **kwargs) + + def __call__(self, *args: Any, **kwargs: Any) -> None: # noqa: ARG002 + debug._print_debug_info() + sys.exit(0) + + +def _print_data(data: str, output_file: str | IO | None) -> None: + if isinstance(output_file, str): + with open(output_file, "w") as fd: # noqa: PTH123 + print(data, file=fd) + else: + if output_file is None: + output_file = sys.stdout + print(data, file=output_file) + + +def _load_packages( + packages: Sequence[str], + *, + extensions: Extensions | None = None, + search_paths: Sequence[str | Path] | None = None, + docstring_parser: DocstringStyle | Parser | None = None, + docstring_options: DocstringOptions | None = None, + resolve_aliases: bool = True, + resolve_implicit: bool = False, + resolve_external: bool | None = None, + allow_inspection: bool = True, + force_inspection: bool = False, + store_source: bool = True, + find_stubs_package: bool = False, +) -> GriffeLoader: + # Create a single loader. + loader = GriffeLoader( + extensions=extensions, + search_paths=search_paths, + docstring_parser=docstring_parser, + docstring_options=docstring_options, + allow_inspection=allow_inspection, + force_inspection=force_inspection, + store_source=store_source, + ) + + # Load each package. + for package in packages: + if not package: + logger.debug("Empty package name, continuing") + continue + logger.info("Loading package %s", package) + try: + loader.load(package, try_relative_path=True, find_stubs_package=find_stubs_package) + except ModuleNotFoundError as error: + logger.error("Could not find package %s: %s", package, error) + except ImportError: + logger.exception("Tried but could not import package %s", package) + logger.info("Finished loading packages") + + # Resolve aliases. + if resolve_aliases: + logger.info("Starting alias resolution") + unresolved, iterations = loader.resolve_aliases(implicit=resolve_implicit, external=resolve_external) + if unresolved: + logger.info("%s aliases were still unresolved after %s iterations", len(unresolved), iterations) + else: + logger.info("All aliases were resolved after %s iterations", iterations) + return loader + + +_level_choices = ("DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL") + + +def _extensions_type(value: str) -> Sequence[str | dict[str, Any]]: + try: + return json.loads(value) + except json.JSONDecodeError: + return value.split(",") + + +def get_parser() -> argparse.ArgumentParser: + """Return the CLI argument parser. + + Returns: + An argparse parser. + """ + usage = "%(prog)s [GLOBAL_OPTS...] COMMAND [COMMAND_OPTS...]" + description = "Signatures for entire Python programs. " + "Extract the structure, the frame, the skeleton of your project, " + "to generate API documentation or find breaking changes in your API." + parser = argparse.ArgumentParser(add_help=False, usage=usage, description=description, prog="griffe") + + main_help = "Show this help message and exit. Commands also accept the -h/--help option." + subcommand_help = "Show this help message and exit." + + global_options = parser.add_argument_group(title="Global options") + global_options.add_argument("-h", "--help", action="help", help=main_help) + global_options.add_argument("-V", "--version", action="version", version=f"%(prog)s {debug._get_version()}") + global_options.add_argument("--debug-info", action=_DebugInfo, help="Print debug information.") + + def add_common_options(subparser: argparse.ArgumentParser) -> None: + common_options = subparser.add_argument_group(title="Common options") + common_options.add_argument("-h", "--help", action="help", help=subcommand_help) + search_options = subparser.add_argument_group(title="Search options") + search_options.add_argument( + "-s", + "--search", + dest="search_paths", + action="append", + type=Path, + help="Paths to search packages into.", + ) + search_options.add_argument( + "-y", + "--sys-path", + dest="append_sys_path", + action="store_true", + help="Whether to append `sys.path` to search paths specified with `-s`.", + ) + loading_options = subparser.add_argument_group(title="Loading options") + loading_options.add_argument( + "-B", + "--find-stubs-packages", + dest="find_stubs_package", + action="store_true", + default=False, + help="Whether to look for stubs-only packages and merge them with concrete ones.", + ) + loading_options.add_argument( + "-e", + "--extensions", + default={}, + type=_extensions_type, + help="A list of extensions to use.", + ) + loading_options.add_argument( + "-X", + "--no-inspection", + dest="allow_inspection", + action="store_false", + default=True, + help="Disallow inspection of builtin/compiled/not found modules.", + ) + loading_options.add_argument( + "-x", + "--force-inspection", + dest="force_inspection", + action="store_true", + default=False, + help="Force inspection of everything, even when sources are found.", + ) + debug_options = subparser.add_argument_group(title="Debugging options") + debug_options.add_argument( + "-L", + "--log-level", + metavar="LEVEL", + default=DEFAULT_LOG_LEVEL, + choices=_level_choices, + type=str.upper, + help="Set the log level: `DEBUG`, `INFO`, `WARNING`, `ERROR`, `CRITICAL`.", + ) + + # ========= SUBPARSERS ========= # + subparsers = parser.add_subparsers( + dest="subcommand", + title="Commands", + metavar="COMMAND", + prog="griffe", + required=True, + ) + + def add_subparser(command: str, text: str, **kwargs: Any) -> argparse.ArgumentParser: + return subparsers.add_parser(command, add_help=False, help=text, description=text, **kwargs) + + # ========= DUMP PARSER ========= # + dump_parser = add_subparser("dump", "Load package-signatures and dump them as JSON.") + dump_options = dump_parser.add_argument_group(title="Dump options") + dump_options.add_argument("packages", metavar="PACKAGE", nargs="+", help="Packages to find, load and dump.") + dump_options.add_argument( + "-f", + "--full", + action="store_true", + default=False, + help="Whether to dump full data in JSON.", + ) + dump_options.add_argument( + "-o", + "--output", + default=sys.stdout, + help="Output file. Supports templating to output each package in its own file, with `{package}`.", + ) + dump_options.add_argument( + "-d", + "--docstyle", + dest="docstring_parser", + default=None, + type=Parser, + help="The docstring style to parse.", + ) + dump_options.add_argument( + "-D", + "--docopts", + dest="docstring_options", + default={}, + type=json.loads, + help="The options for the docstring parser.", + ) + dump_options.add_argument( + "-r", + "--resolve-aliases", + action="store_true", + help="Whether to resolve aliases.", + ) + dump_options.add_argument( + "-I", + "--resolve-implicit", + action="store_true", + help="Whether to resolve implicitly exported aliases as well. " + "Aliases are explicitly exported when defined in `__all__`.", + ) + dump_options.add_argument( + "-U", + "--resolve-external", + dest="resolve_external", + action="store_true", + help="Always resolve aliases pointing to external/unknown modules (not loaded directly)." + "Default is to resolve only from one module to its private sibling (`ast` -> `_ast`).", + ) + dump_options.add_argument( + "--no-resolve-external", + dest="resolve_external", + action="store_false", + help="Never resolve aliases pointing to external/unknown modules (not loaded directly)." + "Default is to resolve only from one module to its private sibling (`ast` -> `_ast`).", + ) + dump_options.add_argument( + "-S", + "--stats", + action="store_true", + help="Show statistics at the end.", + ) + add_common_options(dump_parser) + + # ========= CHECK PARSER ========= # + check_parser = add_subparser("check", "Check for API breakages or possible improvements.") + check_options = check_parser.add_argument_group(title="Check options") + check_options.add_argument("package", metavar="PACKAGE", help="Package to find, load and check, as path.") + check_options.add_argument( + "-a", + "--against", + metavar="REF", + help="Older Git reference (commit, branch, tag) to check against. Default: load latest tag.", + ) + check_options.add_argument( + "-b", + "--base-ref", + metavar="BASE_REF", + help="Git reference (commit, branch, tag) to check. Default: load current code.", + ) + check_options.add_argument( + "--color", + dest="color", + action="store_true", + default=None, + help="Force enable colors in the output.", + ) + check_options.add_argument( + "--no-color", + dest="color", + action="store_false", + default=None, + help="Force disable colors in the output.", + ) + check_options.add_argument("-v", "--verbose", action="store_true", help="Verbose output.") + formats = [fmt.value for fmt in ExplanationStyle] + check_options.add_argument("-f", "--format", dest="style", choices=formats, default=None, help="Output format.") + add_common_options(check_parser) + + return parser + + +def dump( + packages: Sequence[str], + *, + output: str | IO | None = None, + full: bool = False, + docstring_parser: DocstringStyle | Parser | None = None, + docstring_options: DocstringOptions | None = None, + extensions: Sequence[str | dict[str, Any] | Extension | type[Extension]] | None = None, + resolve_aliases: bool = False, + resolve_implicit: bool = False, + resolve_external: bool | None = None, + search_paths: Sequence[str | Path] | None = None, + find_stubs_package: bool = False, + append_sys_path: bool = False, + allow_inspection: bool = True, + force_inspection: bool = False, + stats: bool = False, +) -> int: + """Load packages data and dump it as JSON. + + Parameters: + packages: The packages to load and dump. + output: Where to output the JSON-serialized data. + full: Whether to output full or minimal data. + docstring_parser: The docstring parser to use. By default, no parsing is done. + docstring_options: Docstring parsing options. + resolve_aliases: Whether to resolve aliases (indirect objects references). + resolve_implicit: Whether to resolve every alias or only the explicitly exported ones. + resolve_external: Whether to load additional, unspecified modules to resolve aliases. + Default is to resolve only from one module to its private sibling (`ast` -> `_ast`). + extensions: The extensions to use. + search_paths: The paths to search into. + find_stubs_package: Whether to search for stubs-only packages. + If both the package and its stubs are found, they'll be merged together. + If only the stubs are found, they'll be used as the package itself. + append_sys_path: Whether to append the contents of `sys.path` to the search paths. + allow_inspection: Whether to allow inspecting modules when visiting them is not possible. + force_inspection: Whether to force using dynamic analysis when loading data. + stats: Whether to compute and log stats about loading. + + Returns: + `0` for success, `1` for failure. + """ + # Prepare options. + per_package_output = False + if isinstance(output, str) and output.format(package="package") != output: + per_package_output = True + + search_paths = list(search_paths) if search_paths else [] + if append_sys_path: + search_paths.extend(sys.path) + + try: + loaded_extensions = load_extensions(*(extensions or ())) + except ExtensionError: + logger.exception("Could not load extensions") + return 1 + + # Load packages. + loader = _load_packages( + packages, + extensions=loaded_extensions, + search_paths=search_paths, + docstring_parser=docstring_parser, + docstring_options=docstring_options, + resolve_aliases=resolve_aliases, + resolve_implicit=resolve_implicit, + resolve_external=resolve_external, + allow_inspection=allow_inspection, + force_inspection=force_inspection, + store_source=False, + find_stubs_package=find_stubs_package, + ) + data_packages = loader.modules_collection.members + + # Serialize and dump packages. + started = datetime.now(tz=timezone.utc) + if per_package_output: + for package_name, data in data_packages.items(): + serialized = data.as_json(indent=2, full=full, sort_keys=True) + _print_data(serialized, output.format(package=package_name)) # type: ignore[union-attr] + else: + serialized = json.dumps(data_packages, cls=JSONEncoder, indent=2, full=full, sort_keys=True) + _print_data(serialized, output) + elapsed = datetime.now(tz=timezone.utc) - started + + if stats: + loader_stats = loader.stats() + loader_stats.time_spent_serializing = elapsed.microseconds + logger.info(loader_stats.as_text()) + + return 0 if len(data_packages) == len(packages) else 1 + + +def check( + package: str | Path, + against: str | None = None, + against_path: str | Path | None = None, + *, + base_ref: str | None = None, + extensions: Sequence[str | dict[str, Any] | Extension | type[Extension]] | None = None, + search_paths: Sequence[str | Path] | None = None, + append_sys_path: bool = False, + find_stubs_package: bool = False, + allow_inspection: bool = True, + force_inspection: bool = False, + verbose: bool = False, + color: bool | None = None, + style: str | ExplanationStyle | None = None, +) -> int: + """Check for API breaking changes in two versions of the same package. + + Parameters: + package: The package to load and check. + against: Older Git reference (commit, branch, tag) to check against. + against_path: Path when the "against" reference is checked out. + base_ref: Git reference (commit, branch, tag) to check. + extensions: The extensions to use. + search_paths: The paths to search into. + append_sys_path: Whether to append the contents of `sys.path` to the search paths. + allow_inspection: Whether to allow inspecting modules when visiting them is not possible. + force_inspection: Whether to force using dynamic analysis when loading data. + verbose: Use a verbose output. + + Returns: + `0` for success, `1` for failure. + """ + # Prepare options. + search_paths = list(search_paths) if search_paths else [] + if append_sys_path: + search_paths.extend(sys.path) + + against_path = against_path or package + try: + against = against or _get_latest_tag(package) + repository = _get_repo_root(against_path) + except GitError as error: + print(f"griffe: error: {error}", file=sys.stderr) + return 2 + + try: + loaded_extensions = load_extensions(*(extensions or ())) + except ExtensionError: + logger.exception("Could not load extensions") + return 1 + + # Load old and new version of the package. + old_package = load_git( + against_path, + ref=against, + repo=repository, + extensions=loaded_extensions, + search_paths=search_paths, + allow_inspection=allow_inspection, + force_inspection=force_inspection, + resolve_aliases=True, + resolve_external=None, + ) + if base_ref: + new_package = load_git( + package, + ref=base_ref, + repo=repository, + extensions=loaded_extensions, + search_paths=search_paths, + allow_inspection=allow_inspection, + force_inspection=force_inspection, + find_stubs_package=find_stubs_package, + resolve_aliases=True, + resolve_external=None, + ) + else: + new_package = load( + package, + try_relative_path=True, + extensions=loaded_extensions, + search_paths=search_paths, + allow_inspection=allow_inspection, + force_inspection=force_inspection, + find_stubs_package=find_stubs_package, + resolve_aliases=True, + resolve_external=None, + ) + + # Find and display API breakages. + breakages = list(find_breaking_changes(old_package, new_package)) + + if color is None and (force_color := os.getenv("FORCE_COLOR", None)) is not None: + color = force_color.lower() in {"1", "true", "y", "yes", "on"} + colorama.deinit() + colorama.init(strip=color if color is None else not color) + + if style is None: + style = ExplanationStyle.VERBOSE if verbose else ExplanationStyle.ONE_LINE + else: + style = ExplanationStyle(style) + for breakage in breakages: + print(breakage.explain(style=style), file=sys.stderr) + + if breakages: + return 1 + return 0 + + +def main(args: list[str] | None = None) -> int: + """Run the main program. + + This function is executed when you type `griffe` or `python -m griffe`. + + Parameters: + args: Arguments passed from the command line. + + Returns: + An exit code. + """ + # Parse arguments. + parser = get_parser() + opts: argparse.Namespace = parser.parse_args(args) + opts_dict = opts.__dict__ + opts_dict.pop("debug_info") + subcommand = opts_dict.pop("subcommand") + + # Initialize logging. + log_level = opts_dict.pop("log_level", DEFAULT_LOG_LEVEL) + try: + level = getattr(logging, log_level) + except AttributeError: + choices = "', '".join(_level_choices) + print( + f"griffe: error: invalid log level '{log_level}' (choose from '{choices}')", + file=sys.stderr, + ) + return 1 + else: + logging.basicConfig(format="%(levelname)-10s %(message)s", level=level) + + # Increase maximum recursion limit to 2000. + sys.setrecursionlimit(max(2000, sys.getrecursionlimit())) + + # Run subcommand. + commands: dict[str, Callable[..., int]] = {"check": check, "dump": dump} + return commands[subcommand](**opts_dict) diff --git a/src/griffe/py.typed b/packages/griffe/src/griffe/_internal/py.typed similarity index 100% rename from src/griffe/py.typed rename to packages/griffe/src/griffe/_internal/py.typed diff --git a/packages/griffe/src/griffe/py.typed b/packages/griffe/src/griffe/py.typed new file mode 100644 index 00000000..e69de29b diff --git a/packages/griffelib/LICENSE b/packages/griffelib/LICENSE new file mode 100644 index 00000000..8becbc45 --- /dev/null +++ b/packages/griffelib/LICENSE @@ -0,0 +1,15 @@ +ISC License + +Copyright (c) 2021, Timothée Mazzucotelli + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. diff --git a/packages/griffelib/README.md b/packages/griffelib/README.md new file mode 100644 index 00000000..42bc0890 --- /dev/null +++ b/packages/griffelib/README.md @@ -0,0 +1,115 @@ +# Griffe (lib) + +[![ci](https://github.com/mkdocstrings/griffe/workflows/ci/badge.svg)](https://github.com/mkdocstrings/griffe/actions?query=workflow%3Aci) +[![documentation](https://img.shields.io/badge/docs-mkdocs-708FCC.svg?style=flat)](https://mkdocstrings.github.io/griffe/) +[![pypi version](https://img.shields.io/pypi/v/griffe.svg)](https://pypi.org/project/griffe/) +[![gitter](https://img.shields.io/badge/matrix-chat-4db798.svg?style=flat)](https://app.gitter.im/#/room/#mkdocstrings_griffe:gitter.im) +[![radicle](https://img.shields.io/badge/rad-clone-6666FF.svg?style=flat)](https://app.radicle.at/nodes/seed.radicle.at/rad:z4M5XTPDD4Wh1sm8iPCenF85J3z8Z) + +Griffe logo, created by François Rozet + +Signatures for entire Python programs. Extract the structure, the frame, the skeleton of your project, to generate API documentation or find breaking changes in your API. + +Griffe, pronounced "grif" (`/ɡʁif/`), is a french word that means "claw", +but also "signature" in a familiar way. "On reconnaît bien là sa griffe." + +- [User guide](https://mkdocstrings.github.io/griffe/guide/users/) +- [Contributor guide](https://mkdocstrings.github.io/griffe/guide/contributors/) +- [API reference](https://mkdocstrings.github.io/griffe/reference/api/) + +## Installation + +```bash +pip install griffe +``` + +With [`uv`](https://docs.astral.sh/uv/): + +```bash +uv tool install griffe +``` + +## Usage + +### Dump JSON-serialized API + +**On the command line**, pass the names of packages to the `griffe dump` command: + +```console +$ griffe dump httpx fastapi +{ + "httpx": { + "name": "httpx", + ... + }, + "fastapi": { + "name": "fastapi", + ... + } +} +``` + +See the [Serializing chapter](https://mkdocstrings.github.io/griffe/guide/users/serializing/) for more examples. + +### Check for API breaking changes + +Pass a relative path to the `griffe check` command: + +```console +$ griffe check mypackage --verbose +mypackage/mymodule.py:10: MyClass.mymethod(myparam): +Parameter kind was changed: + Old: positional or keyword + New: keyword-only +``` + +For `src` layouts: + +```console +$ griffe check --search src mypackage --verbose +src/mypackage/mymodule.py:10: MyClass.mymethod(myparam): +Parameter kind was changed: + Old: positional or keyword + New: keyword-only +``` + +It's also possible to directly **check packages from PyPI.org** +(or other indexes configured through `PIP_INDEX_URL`). +This feature is [available to sponsors only](https://mkdocstrings.github.io/griffe/insiders/) +and requires that you install Griffe with the `pypi` extra: + +```bash +pip install griffe[pypi] +``` + +The command syntax is: + +```bash +griffe check package_name -b project-name==2.0 -a project-name==1.0 +``` + +See the [Checking chapter](https://mkdocstrings.github.io/griffe/guide/users/checking/) for more examples. + +### Load and navigate data with Python + +**With Python**, loading a package: + +```python +import griffe + +fastapi = griffe.load("fastapi") +``` + +Finding breaking changes: + +```python +import griffe + +previous = griffe.load_git("mypackage", ref="0.2.0") +current = griffe.load("mypackage") + +for breakage in griffe.find_breaking_changes(previous, current): + ... +``` + +See the [Loading chapter](https://mkdocstrings.github.io/griffe/guide/users/loading/) for more examples. diff --git a/packages/griffelib/pyproject.toml b/packages/griffelib/pyproject.toml new file mode 100644 index 00000000..e69de29b diff --git a/src/griffe/__init__.py b/packages/griffelib/src/griffelib/__init__.py similarity index 86% rename from src/griffe/__init__.py rename to packages/griffelib/src/griffelib/__init__.py index 0f1f2e9a..b9108166 100644 --- a/src/griffe/__init__.py +++ b/packages/griffelib/src/griffelib/__init__.py @@ -2,7 +2,7 @@ # and exposes them as public objects. We have tests to make sure # no object is forgotten in this list. -"""Griffe package. +"""Griffe package (library). Signatures for entire Python programs. Extract the structure, the frame, the skeleton of your project, @@ -165,9 +165,9 @@ import warnings from typing import Any -from griffe._internal.agents.inspector import Inspector, inspect -from griffe._internal.agents.nodes.assignments import get_instance_names, get_name, get_names -from griffe._internal.agents.nodes.ast import ( +from griffelib._internal.agents.inspector import Inspector, inspect +from griffelib._internal.agents.nodes.assignments import get_instance_names, get_name, get_names +from griffelib._internal.agents.nodes.ast import ( ast_children, ast_first_child, ast_kind, @@ -178,19 +178,19 @@ ast_previous_siblings, ast_siblings, ) -from griffe._internal.agents.nodes.docstrings import get_docstring +from griffelib._internal.agents.nodes.docstrings import get_docstring # YORE: Bump 2: Replace `ExportedName, ` with `` within line. -from griffe._internal.agents.nodes.exports import ExportedName, get__all__, safe_get__all__ -from griffe._internal.agents.nodes.imports import relative_to_absolute -from griffe._internal.agents.nodes.parameters import ParametersType, get_parameters -from griffe._internal.agents.nodes.runtime import ObjectNode -from griffe._internal.agents.nodes.values import get_value, safe_get_value -from griffe._internal.agents.visitor import Visitor, builtin_decorators, stdlib_decorators, typing_overload, visit -from griffe._internal.c3linear import c3linear_merge -from griffe._internal.cli import DEFAULT_LOG_LEVEL, check, dump, get_parser, main -from griffe._internal.collections import LinesCollection, ModulesCollection -from griffe._internal.diff import ( +from griffelib._internal.agents.nodes.exports import ExportedName, get__all__, safe_get__all__ +from griffelib._internal.agents.nodes.imports import relative_to_absolute +from griffelib._internal.agents.nodes.parameters import ParametersType, get_parameters +from griffelib._internal.agents.nodes.runtime import ObjectNode +from griffelib._internal.agents.nodes.values import get_value, safe_get_value +from griffelib._internal.agents.visitor import Visitor, builtin_decorators, stdlib_decorators, typing_overload, visit +from griffelib._internal.c3linear import c3linear_merge +from griffelib._internal.cli import DEFAULT_LOG_LEVEL, check, dump, get_parser, main +from griffelib._internal.collections import LinesCollection, ModulesCollection +from griffelib._internal.diff import ( AttributeChangedTypeBreakage, AttributeChangedValueBreakage, Breakage, @@ -206,8 +206,8 @@ ReturnChangedTypeBreakage, find_breaking_changes, ) -from griffe._internal.docstrings.google import GoogleOptions, parse_google -from griffe._internal.docstrings.models import ( +from griffelib._internal.docstrings.google import GoogleOptions, parse_google +from griffelib._internal.docstrings.models import ( DocstringAdmonition, DocstringAttribute, DocstringClass, @@ -243,8 +243,8 @@ DocstringWarn, DocstringYield, ) -from griffe._internal.docstrings.numpy import NumpyOptions, parse_numpy -from griffe._internal.docstrings.parsers import ( +from griffelib._internal.docstrings.numpy import NumpyOptions, parse_numpy +from griffelib._internal.docstrings.parsers import ( DocstringDetectionMethod, DocstringOptions, DocstringStyle, @@ -253,10 +253,10 @@ parse_auto, parsers, ) -from griffe._internal.docstrings.sphinx import SphinxOptions, parse_sphinx -from griffe._internal.docstrings.utils import docstring_warning, parse_docstring_annotation -from griffe._internal.encoders import JSONEncoder, json_decoder -from griffe._internal.enumerations import ( +from griffelib._internal.docstrings.sphinx import SphinxOptions, parse_sphinx +from griffelib._internal.docstrings.utils import docstring_warning, parse_docstring_annotation +from griffelib._internal.encoders import JSONEncoder, json_decoder +from griffelib._internal.enumerations import ( BreakageKind, DocstringSectionKind, ExplanationStyle, @@ -267,7 +267,7 @@ Parser, TypeParameterKind, ) -from griffe._internal.exceptions import ( +from griffelib._internal.exceptions import ( AliasResolutionError, BuiltinModuleError, CyclicAliasError, @@ -282,7 +282,7 @@ UnhandledEditableModuleError, UnimportableModuleError, ) -from griffe._internal.expressions import ( +from griffelib._internal.expressions import ( Expr, ExprAttribute, ExprBinOp, @@ -324,28 +324,28 @@ safe_get_condition, safe_get_expression, ) -from griffe._internal.extensions.base import ( +from griffelib._internal.extensions.base import ( Extension, Extensions, LoadableExtensionType, builtin_extensions, load_extensions, ) -from griffe._internal.extensions.dataclasses import DataclassesExtension -from griffe._internal.finder import ModuleFinder, NamePartsAndPathType, NamePartsType, NamespacePackage, Package -from griffe._internal.git import GitInfo, KnownGitService -from griffe._internal.importer import dynamic_import, sys_path -from griffe._internal.loader import GriffeLoader, load, load_git, load_pypi -from griffe._internal.logger import Logger, get_logger, logger, patch_loggers -from griffe._internal.merger import merge_stubs -from griffe._internal.mixins import ( +from griffelib._internal.extensions.dataclasses import DataclassesExtension +from griffelib._internal.finder import ModuleFinder, NamePartsAndPathType, NamePartsType, NamespacePackage, Package +from griffelib._internal.git import GitInfo, KnownGitService +from griffelib._internal.importer import dynamic_import, sys_path +from griffelib._internal.loader import GriffeLoader, load, load_git, load_pypi +from griffelib._internal.logger import Logger, get_logger, logger, patch_loggers +from griffelib._internal.merger import merge_stubs +from griffelib._internal.mixins import ( DelMembersMixin, GetMembersMixin, ObjectAliasMixin, SerializationMixin, SetMembersMixin, ) -from griffe._internal.models import ( +from griffelib._internal.models import ( Alias, Attribute, Class, @@ -360,8 +360,8 @@ TypeParameter, TypeParameters, ) -from griffe._internal.stats import Stats -from griffe._internal.tests import ( +from griffelib._internal.stats import Stats +from griffelib._internal.tests import ( TmpPackage, htree, module_vtree, @@ -386,12 +386,12 @@ # YORE: Bump 2: Remove block. def __getattr__(name: str) -> Any: if name in _deprecated_names: - from griffe._internal import git # noqa: PLC0415 + from griffelib._internal import git # noqa: PLC0415 warnings.warn( f"The `{name}` function is deprecated and will become unavailable in the next major version.", DeprecationWarning, - stacklevel=2, + stacklevel=3, ) return getattr(git, f"_{name}") diff --git a/src/griffe/_internal/__init__.py b/packages/griffelib/src/griffelib/_internal/__init__.py similarity index 100% rename from src/griffe/_internal/__init__.py rename to packages/griffelib/src/griffelib/_internal/__init__.py diff --git a/src/griffe/_internal/agents/__init__.py b/packages/griffelib/src/griffelib/_internal/agents/__init__.py similarity index 100% rename from src/griffe/_internal/agents/__init__.py rename to packages/griffelib/src/griffelib/_internal/agents/__init__.py diff --git a/src/griffe/_internal/agents/inspector.py b/packages/griffelib/src/griffelib/_internal/agents/inspector.py similarity index 100% rename from src/griffe/_internal/agents/inspector.py rename to packages/griffelib/src/griffelib/_internal/agents/inspector.py diff --git a/src/griffe/_internal/agents/nodes/__init__.py b/packages/griffelib/src/griffelib/_internal/agents/nodes/__init__.py similarity index 100% rename from src/griffe/_internal/agents/nodes/__init__.py rename to packages/griffelib/src/griffelib/_internal/agents/nodes/__init__.py diff --git a/src/griffe/_internal/agents/nodes/assignments.py b/packages/griffelib/src/griffelib/_internal/agents/nodes/assignments.py similarity index 100% rename from src/griffe/_internal/agents/nodes/assignments.py rename to packages/griffelib/src/griffelib/_internal/agents/nodes/assignments.py diff --git a/src/griffe/_internal/agents/nodes/ast.py b/packages/griffelib/src/griffelib/_internal/agents/nodes/ast.py similarity index 100% rename from src/griffe/_internal/agents/nodes/ast.py rename to packages/griffelib/src/griffelib/_internal/agents/nodes/ast.py diff --git a/src/griffe/_internal/agents/nodes/docstrings.py b/packages/griffelib/src/griffelib/_internal/agents/nodes/docstrings.py similarity index 100% rename from src/griffe/_internal/agents/nodes/docstrings.py rename to packages/griffelib/src/griffelib/_internal/agents/nodes/docstrings.py diff --git a/src/griffe/_internal/agents/nodes/exports.py b/packages/griffelib/src/griffelib/_internal/agents/nodes/exports.py similarity index 100% rename from src/griffe/_internal/agents/nodes/exports.py rename to packages/griffelib/src/griffelib/_internal/agents/nodes/exports.py diff --git a/src/griffe/_internal/agents/nodes/imports.py b/packages/griffelib/src/griffelib/_internal/agents/nodes/imports.py similarity index 100% rename from src/griffe/_internal/agents/nodes/imports.py rename to packages/griffelib/src/griffelib/_internal/agents/nodes/imports.py diff --git a/src/griffe/_internal/agents/nodes/parameters.py b/packages/griffelib/src/griffelib/_internal/agents/nodes/parameters.py similarity index 100% rename from src/griffe/_internal/agents/nodes/parameters.py rename to packages/griffelib/src/griffelib/_internal/agents/nodes/parameters.py diff --git a/src/griffe/_internal/agents/nodes/runtime.py b/packages/griffelib/src/griffelib/_internal/agents/nodes/runtime.py similarity index 100% rename from src/griffe/_internal/agents/nodes/runtime.py rename to packages/griffelib/src/griffelib/_internal/agents/nodes/runtime.py diff --git a/src/griffe/_internal/agents/nodes/values.py b/packages/griffelib/src/griffelib/_internal/agents/nodes/values.py similarity index 100% rename from src/griffe/_internal/agents/nodes/values.py rename to packages/griffelib/src/griffelib/_internal/agents/nodes/values.py diff --git a/src/griffe/_internal/agents/visitor.py b/packages/griffelib/src/griffelib/_internal/agents/visitor.py similarity index 100% rename from src/griffe/_internal/agents/visitor.py rename to packages/griffelib/src/griffelib/_internal/agents/visitor.py diff --git a/src/griffe/_internal/c3linear.py b/packages/griffelib/src/griffelib/_internal/c3linear.py similarity index 100% rename from src/griffe/_internal/c3linear.py rename to packages/griffelib/src/griffelib/_internal/c3linear.py diff --git a/src/griffe/_internal/cli.py b/packages/griffelib/src/griffelib/_internal/cli.py similarity index 100% rename from src/griffe/_internal/cli.py rename to packages/griffelib/src/griffelib/_internal/cli.py diff --git a/src/griffe/_internal/collections.py b/packages/griffelib/src/griffelib/_internal/collections.py similarity index 100% rename from src/griffe/_internal/collections.py rename to packages/griffelib/src/griffelib/_internal/collections.py diff --git a/src/griffe/_internal/debug.py b/packages/griffelib/src/griffelib/_internal/debug.py similarity index 100% rename from src/griffe/_internal/debug.py rename to packages/griffelib/src/griffelib/_internal/debug.py diff --git a/src/griffe/_internal/diff.py b/packages/griffelib/src/griffelib/_internal/diff.py similarity index 100% rename from src/griffe/_internal/diff.py rename to packages/griffelib/src/griffelib/_internal/diff.py diff --git a/src/griffe/_internal/docstrings/__init__.py b/packages/griffelib/src/griffelib/_internal/docstrings/__init__.py similarity index 100% rename from src/griffe/_internal/docstrings/__init__.py rename to packages/griffelib/src/griffelib/_internal/docstrings/__init__.py diff --git a/src/griffe/_internal/docstrings/google.py b/packages/griffelib/src/griffelib/_internal/docstrings/google.py similarity index 100% rename from src/griffe/_internal/docstrings/google.py rename to packages/griffelib/src/griffelib/_internal/docstrings/google.py diff --git a/src/griffe/_internal/docstrings/models.py b/packages/griffelib/src/griffelib/_internal/docstrings/models.py similarity index 100% rename from src/griffe/_internal/docstrings/models.py rename to packages/griffelib/src/griffelib/_internal/docstrings/models.py diff --git a/src/griffe/_internal/docstrings/numpy.py b/packages/griffelib/src/griffelib/_internal/docstrings/numpy.py similarity index 100% rename from src/griffe/_internal/docstrings/numpy.py rename to packages/griffelib/src/griffelib/_internal/docstrings/numpy.py diff --git a/src/griffe/_internal/docstrings/parsers.py b/packages/griffelib/src/griffelib/_internal/docstrings/parsers.py similarity index 100% rename from src/griffe/_internal/docstrings/parsers.py rename to packages/griffelib/src/griffelib/_internal/docstrings/parsers.py diff --git a/src/griffe/_internal/docstrings/sphinx.py b/packages/griffelib/src/griffelib/_internal/docstrings/sphinx.py similarity index 100% rename from src/griffe/_internal/docstrings/sphinx.py rename to packages/griffelib/src/griffelib/_internal/docstrings/sphinx.py diff --git a/src/griffe/_internal/docstrings/utils.py b/packages/griffelib/src/griffelib/_internal/docstrings/utils.py similarity index 100% rename from src/griffe/_internal/docstrings/utils.py rename to packages/griffelib/src/griffelib/_internal/docstrings/utils.py diff --git a/src/griffe/_internal/encoders.py b/packages/griffelib/src/griffelib/_internal/encoders.py similarity index 100% rename from src/griffe/_internal/encoders.py rename to packages/griffelib/src/griffelib/_internal/encoders.py diff --git a/src/griffe/_internal/enumerations.py b/packages/griffelib/src/griffelib/_internal/enumerations.py similarity index 100% rename from src/griffe/_internal/enumerations.py rename to packages/griffelib/src/griffelib/_internal/enumerations.py diff --git a/src/griffe/_internal/exceptions.py b/packages/griffelib/src/griffelib/_internal/exceptions.py similarity index 100% rename from src/griffe/_internal/exceptions.py rename to packages/griffelib/src/griffelib/_internal/exceptions.py diff --git a/src/griffe/_internal/expressions.py b/packages/griffelib/src/griffelib/_internal/expressions.py similarity index 100% rename from src/griffe/_internal/expressions.py rename to packages/griffelib/src/griffelib/_internal/expressions.py diff --git a/src/griffe/_internal/extensions/__init__.py b/packages/griffelib/src/griffelib/_internal/extensions/__init__.py similarity index 100% rename from src/griffe/_internal/extensions/__init__.py rename to packages/griffelib/src/griffelib/_internal/extensions/__init__.py diff --git a/src/griffe/_internal/extensions/base.py b/packages/griffelib/src/griffelib/_internal/extensions/base.py similarity index 100% rename from src/griffe/_internal/extensions/base.py rename to packages/griffelib/src/griffelib/_internal/extensions/base.py diff --git a/src/griffe/_internal/extensions/dataclasses.py b/packages/griffelib/src/griffelib/_internal/extensions/dataclasses.py similarity index 100% rename from src/griffe/_internal/extensions/dataclasses.py rename to packages/griffelib/src/griffelib/_internal/extensions/dataclasses.py diff --git a/src/griffe/_internal/finder.py b/packages/griffelib/src/griffelib/_internal/finder.py similarity index 100% rename from src/griffe/_internal/finder.py rename to packages/griffelib/src/griffelib/_internal/finder.py diff --git a/src/griffe/_internal/git.py b/packages/griffelib/src/griffelib/_internal/git.py similarity index 100% rename from src/griffe/_internal/git.py rename to packages/griffelib/src/griffelib/_internal/git.py diff --git a/src/griffe/_internal/importer.py b/packages/griffelib/src/griffelib/_internal/importer.py similarity index 100% rename from src/griffe/_internal/importer.py rename to packages/griffelib/src/griffelib/_internal/importer.py diff --git a/src/griffe/_internal/loader.py b/packages/griffelib/src/griffelib/_internal/loader.py similarity index 100% rename from src/griffe/_internal/loader.py rename to packages/griffelib/src/griffelib/_internal/loader.py diff --git a/src/griffe/_internal/logger.py b/packages/griffelib/src/griffelib/_internal/logger.py similarity index 100% rename from src/griffe/_internal/logger.py rename to packages/griffelib/src/griffelib/_internal/logger.py diff --git a/src/griffe/_internal/merger.py b/packages/griffelib/src/griffelib/_internal/merger.py similarity index 100% rename from src/griffe/_internal/merger.py rename to packages/griffelib/src/griffelib/_internal/merger.py diff --git a/src/griffe/_internal/mixins.py b/packages/griffelib/src/griffelib/_internal/mixins.py similarity index 100% rename from src/griffe/_internal/mixins.py rename to packages/griffelib/src/griffelib/_internal/mixins.py diff --git a/src/griffe/_internal/models.py b/packages/griffelib/src/griffelib/_internal/models.py similarity index 100% rename from src/griffe/_internal/models.py rename to packages/griffelib/src/griffelib/_internal/models.py diff --git a/packages/griffelib/src/griffelib/_internal/py.typed b/packages/griffelib/src/griffelib/_internal/py.typed new file mode 100644 index 00000000..e69de29b diff --git a/src/griffe/_internal/stats.py b/packages/griffelib/src/griffelib/_internal/stats.py similarity index 100% rename from src/griffe/_internal/stats.py rename to packages/griffelib/src/griffelib/_internal/stats.py diff --git a/src/griffe/_internal/tests.py b/packages/griffelib/src/griffelib/_internal/tests.py similarity index 100% rename from src/griffe/_internal/tests.py rename to packages/griffelib/src/griffelib/_internal/tests.py diff --git a/packages/griffelib/src/griffelib/py.typed b/packages/griffelib/src/griffelib/py.typed new file mode 100644 index 00000000..e69de29b diff --git a/tests/helpers.py b/tests/helpers.py index 47613ddd..1ca06eae 100644 --- a/tests/helpers.py +++ b/tests/helpers.py @@ -6,7 +6,7 @@ import sys from tempfile import gettempdir -from griffe._internal.tests import _TMPDIR_PREFIX +from griffelib._internal.tests import _TMPDIR_PREFIX def clear_sys_modules(name: str | None = None) -> None: diff --git a/tests/test_encoders.py b/tests/test_encoders.py index e6e6debb..3ce6f657 100644 --- a/tests/test_encoders.py +++ b/tests/test_encoders.py @@ -8,7 +8,7 @@ import pytest from jsonschema import ValidationError, validate -from griffe import Attribute, Class, Function, GriffeLoader, Kind, Module, Object, temporary_visited_module +from griffelib import Attribute, Class, Function, GriffeLoader, Kind, Module, Object, temporary_visited_module def test_minimal_data_is_enough() -> None: