diff --git a/cookie_composer/authentication.py b/cookie_composer/authentication.py index 53adc8e..cf0884b 100644 --- a/cookie_composer/authentication.py +++ b/cookie_composer/authentication.py @@ -88,7 +88,7 @@ def add_auth_to_url(url: str) -> str: def github_auth_device(n_polls: int = 9999) -> Optional[str]: # pragma: no cover """ - Authenticate with GitHub, polling up to ``n_polls`` times to wait for completion. + Authenticate with GitHub, polling up to `n_polls` times to wait for completion. """ from ghapi.auth import GhDeviceAuth diff --git a/cookie_composer/cc_overrides.py b/cookie_composer/cc_overrides.py index e18a743..3486553 100644 --- a/cookie_composer/cc_overrides.py +++ b/cookie_composer/cc_overrides.py @@ -19,7 +19,7 @@ def jsonify_context(value: Any) -> MutableMapping: - """Convert a ``Context`` to a dict.""" + """Convert a `Context` to a dict.""" if isinstance(value, Context): return value.flatten() @@ -61,7 +61,7 @@ def _read_extensions(self, context: MutableMapping[str, Any]) -> List[str]: list instead. Args: - context: A ``dict`` possibly containing the ``_extensions`` key + context: A `dict` possibly containing the `_extensions` key Returns: List of extensions as str to be passed on to the Jinja2 env @@ -95,7 +95,7 @@ def prompt_for_config( prompts: A dictionary of configuration prompts and default values aggregated_context: An existing configuration to use as a basis layer_context: A dictionary of defaults defined in the layer - no_input: If ``True`` Don't prompt the user at command line for manual configuration + no_input: If `True` Don't prompt the user at command line for manual configuration Returns: A new configuration context diff --git a/cookie_composer/cli.py b/cookie_composer/cli.py index 87b9cfd..7bcc3bb 100644 --- a/cookie_composer/cli.py +++ b/cookie_composer/cli.py @@ -36,7 +36,7 @@ def validate_context_params(ctx: Any, param: Any, value: list) -> Optional[Order Convert a tuple to a dict - e.g.: ``('program_name=foobar', 'startsecs=66')`` -> ``{'program_name': 'foobar', 'startsecs': '66'}`` + e.g.: `('program_name=foobar', 'startsecs=66')` -> `{'program_name': 'foobar', 'startsecs': '66'}` Arguments: ctx: Click context (unused) @@ -44,10 +44,10 @@ def validate_context_params(ctx: Any, param: Any, value: list) -> Optional[Order value: Click parameter value Returns: - An ordered dict of the parameter values or ``None`` if no parameters. + An ordered dict of the parameter values or `None` if no parameters. Raises: - BadParameter: If the parameters are not ``key=value``. + BadParameter: If the parameters are not `key=value`. """ for string in value: if "=" not in string: diff --git a/cookie_composer/commands/add.py b/cookie_composer/commands/add.py index 1853786..5753e33 100644 --- a/cookie_composer/commands/add.py +++ b/cookie_composer/commands/add.py @@ -31,7 +31,7 @@ def add_cmd( Args: path_or_url: A URL or string to add the template or configuration destination_dir: The project directory to add the layer to - no_input: If ``True`` force each layer's ``no_input`` attribute to ``True`` + no_input: If `True` force each layer's `no_input` attribute to `True` checkout: The branch, tag or commit to check out after git clone directory: Directory within repo that holds cookiecutter.json file overwrite_if_exists: Overwrite the contents of the output directory if it already exists diff --git a/cookie_composer/commands/create.py b/cookie_composer/commands/create.py index fee7fe8..0babe4c 100644 --- a/cookie_composer/commands/create.py +++ b/cookie_composer/commands/create.py @@ -32,7 +32,7 @@ def create_cmd( Args: path_or_url: The path or url to the composition file or template output_dir: Where to generate the project - no_input: If ``True`` force each layer's ``no_input`` attribute to ``True`` + no_input: If `True` force each layer's `no_input` attribute to `True` checkout: The branch, tag or commit to check out after git clone directory: Directory within repo that holds cookiecutter.json file overwrite_if_exists: Overwrite the contents of the output directory if it already exists diff --git a/cookie_composer/commands/link.py b/cookie_composer/commands/link.py index 5ea1dc1..3731d40 100644 --- a/cookie_composer/commands/link.py +++ b/cookie_composer/commands/link.py @@ -24,7 +24,7 @@ def link_cmd( Args: path_or_url: A URL or string to add the template or configuration destination_dir: The project directory to add the layer to - no_input: If ``True`` force each layer's ``no_input`` attribute to ``True`` + no_input: If `True` force each layer's `no_input` attribute to `True` checkout: The branch, tag or commit to check out after git clone directory: Directory within repo that holds cookiecutter.json file overwrite_if_exists: Overwrite the contents of the output directory if it already exists diff --git a/cookie_composer/commands/update.py b/cookie_composer/commands/update.py index 847268c..bbd3532 100644 --- a/cookie_composer/commands/update.py +++ b/cookie_composer/commands/update.py @@ -22,7 +22,7 @@ def update_cmd(project_dir: Optional[Path] = None, no_input: bool = False) -> No Args: project_dir: The project directory to update. Defaults to current directory. - no_input: If ``True`` force each layer's ``no_input`` attribute to ``True`` + no_input: If `True` force each layer's `no_input` attribute to `True` Raises: GitError: If the destination_dir is not a git repository @@ -117,17 +117,17 @@ def update_rendered_composition_layers( base: RenderedComposition, updated_layers: List[RenderedLayer] ) -> RenderedComposition: """ - Update ``base.layers`` with ``updated_layers`` where layer names match. + Update `base.layers` with `updated_layers` where layer names match. - If, for some reason, a layer exists in ``updated_layers`` but not in ``base``, it is discarded. + If, for some reason, a layer exists in `updated_layers` but not in `base`, it is discarded. Args: base: The base composition whose layers are to be updated updated_layers: The new rendered layers Raises: - RuntimeError: If a layer's location ``render_dir`` properties don't match - RuntimeError: If the compositions' ``rendered_name`` properties don't match + RuntimeError: If a layer's location `render_dir` properties don't match + RuntimeError: If the compositions' `rendered_name` properties don't match Returns: A new composition with updated layers diff --git a/cookie_composer/composition.py b/cookie_composer/composition.py index 4aa3216..25c9216 100644 --- a/cookie_composer/composition.py +++ b/cookie_composer/composition.py @@ -26,7 +26,7 @@ class RenderedComposition(BaseModel): render_dir: DirectoryPath """The directory in which the layers were rendered. - The ``render_dir`` + ``rendered_name`` is the location of the project.""" + The `render_dir` + `rendered_name` is the location of the project.""" rendered_name: str """The name of the rendered project.""" @@ -41,11 +41,11 @@ def get_context_for_layer(composition: RenderedComposition, index: Optional[int] """ Merge the contexts for all layers up to index. - An ``index`` of ``None`` does all the layers. + An `index` of `None` does all the layers. Args: composition: The rendered composition - index: Merge the contexts of the layers up to this 0-based index. ``None`` to do all layers. + index: Merge the contexts of the layers up to this 0-based index. `None` to do all layers. Returns: The comprehensively merged context diff --git a/cookie_composer/data_merge.py b/cookie_composer/data_merge.py index 1203828..f81ce24 100644 --- a/cookie_composer/data_merge.py +++ b/cookie_composer/data_merge.py @@ -139,10 +139,10 @@ def freeze_data(obj: Any) -> Any: """Do not merge the data, use the file path to determine what to do.""" NESTED_OVERWRITE = "nested-overwrite" -"""Merge deeply nested structures and overwrite at the lowest level; A deep ``dict.update()``.""" +"""Merge deeply nested structures and overwrite at the lowest level; A deep `dict.update()`.""" OVERWRITE = "overwrite" -"""Overwrite at the top level like ``dict.update()``.""" +"""Overwrite at the top level like `dict.update()`.""" COMPREHENSIVE = "comprehensive" """Comprehensively merge the two data structures. @@ -157,7 +157,7 @@ def get_merge_strategy(path: Path, merge_strategies: Dict[str, str]) -> str: """ Return the merge strategy of the path based on the layer configured rules. - Files that are not mergable return :attr:`~cookie_composer.composition.DO_NOT_MERGE` + Files that are not mergable return [DO_NOT_MERGE][cookie_composer.data_merge.DO_NOT_MERGE]. Args: path: The file path to evaluate. diff --git a/cookie_composer/diff.py b/cookie_composer/diff.py index 8517f52..62b41f6 100644 --- a/cookie_composer/diff.py +++ b/cookie_composer/diff.py @@ -56,7 +56,7 @@ def replace_diff_prefixes(diff: str, repo0_path: str, repo1_path: str) -> str: """ Replace the changed file prefixes in the diff output. - Our ``git diff --no-index`` command will output full paths like so:: + Our `git diff --no-index` command will output full paths like so:: --- upstream-template-old/tmp/tmpmp34g21y/remote/.coveragerc +++ upstream-template-new/tmp/tmpmp34g21y/local/.coveragerc @@ -68,8 +68,8 @@ def replace_diff_prefixes(diff: str, repo0_path: str, repo1_path: str) -> str: +++ upstream-template-new/.coveragerc - NIX OPs have ``{prefix}/folder/file`` - WIN OPS have ``{prefix}/c:/folder/file`` + NIX OPs have `{prefix}/folder/file` + WIN OPS have `{prefix}/c:/folder/file` More info on git-diff can be found here: http://git-scm.com/docs/git-diff diff --git a/cookie_composer/git_commands.py b/cookie_composer/git_commands.py index 34ef7a1..720d706 100644 --- a/cookie_composer/git_commands.py +++ b/cookie_composer/git_commands.py @@ -24,8 +24,8 @@ def get_repo( Args: project_dir: The directory containing the .git folder - search_parent_directories: if ``True``, all parent directories will be searched for a valid repo as well. - ensure_clean: if ``True``, raise an error if the repo is dirty + search_parent_directories: if `True`, all parent directories will be searched for a valid repo as well. + ensure_clean: if `True`, raise an error if the repo is dirty Raises: GitError: If the directory is not a git repo @@ -77,7 +77,7 @@ def branch_exists(repo: Repo, branch_name: str) -> bool: branch_name: The name of the branch to check for Returns: - ``True`` if the branch exists + `True` if the branch exists """ return branch_name in repo.refs @@ -89,10 +89,10 @@ def remote_branch_exists(repo: Repo, branch_name: str, remote_name: str = "origi Args: repo: The repository to check branch_name: The name of the branch to check for - remote_name: The name of the remote reference. Defaults to ``origin`` + remote_name: The name of the remote reference. Defaults to `origin` Returns: - ``True`` if the branch exists in the remote repository + `True` if the branch exists in the remote repository """ if remote_name in repo.remotes: return branch_name in repo.remotes[remote_name].refs diff --git a/cookie_composer/io.py b/cookie_composer/io.py index 1c3a1bd..776bce7 100644 --- a/cookie_composer/io.py +++ b/cookie_composer/io.py @@ -28,7 +28,7 @@ def serialize_layer(layer: LayerConfig) -> dict: return layer_info -def deserialize_layer(layer_info: dict, local_path: Optional[Path] = None, **kwargs) -> LayerConfig: +def deserialize_layer(layer_info: dict, local_path: Optional[Path] = None, **kwargs: Any) -> LayerConfig: """Deserialize a layer configuration from a rendered layer.""" from cookie_composer.templates.source import get_template_repo @@ -145,20 +145,20 @@ def write_yaml(path: Path, contents: List[dict]) -> None: def is_composition_file(path_or_url: Union[str, Path]) -> bool: """ - Return ``True`` if the filename a composition file. + Return `True` if the filename a composition file. Args: path_or_url: The path or URL to check Returns: - ``True`` if the path is a configuration file. + `True` if the path is a configuration file. """ return Path(path_or_url).suffix in {".yaml", ".yml"} -def read_composition(path_or_url: Union[str, Path], **kwargs) -> Composition: +def read_composition(path_or_url: Union[str, Path], **kwargs: Any) -> Composition: """ - Read a YAML file and return a :class:`~.Composition`. + Read a YAML file and return a [Composition][cookie_composer.composition.Composition]. Args: path_or_url: The location of the configuration file @@ -176,7 +176,7 @@ def read_composition(path_or_url: Union[str, Path], **kwargs) -> Composition: def read_rendered_composition(path: Path) -> RenderedComposition: """ - Read a ``.composition.yaml`` from a rendered project. + Read a `.composition.yaml` from a rendered project. Args: path: The path to the .composition.yaml file to read @@ -214,14 +214,14 @@ def get_composition_from_path_or_url( initial_context: Optional[MutableMapping[str, Any]] = None, ) -> Composition: """ - Generate a :class:`Composition` from a path or URL. + Generate a [Composition][cookie_composer.composition.Composition] from a path or URL. Args: path_or_url: The path or url to the composition file or template checkout: The branch, tag or commit to check out after git clone default_config: Do not load a config file. Use the defaults instead directory: Directory within repo that holds cookiecutter.json file - no_input: If ``True`` force each layer's ``no_input`` attribute to ``True`` + no_input: If `True` force each layer's `no_input` attribute to `True` output_dir: Where to generate the project overwrite_if_exists: Overwrite the contents of the output directory if it already exists skip_if_file_exists: Skip the files in the corresponding directories if they already exist diff --git a/cookie_composer/layers.py b/cookie_composer/layers.py index ee31e14..0110245 100644 --- a/cookie_composer/layers.py +++ b/cookie_composer/layers.py @@ -98,11 +98,13 @@ def generate_context( Get the context for prompting the user for values. The order of precedence is: + 1. `initial_context` from the composition or command-line 2. `default_context` from the user_config 3. `raw context` from the template - Equivalent to `cookiecutter.generate.generate_context` but with the following differences: + Equivalent to [cookiecutter.generate.generate_context][] but with the following differences: + 1. Reading the raw context file is handled by the layer's template 2. The layer's initial context is treated as the `extra_context` 3. Does not namespace the context with `{"cookiecutter": ...}` @@ -161,7 +163,7 @@ def latest_commit(self) -> Optional[str]: @model_validator(mode="before") @classmethod def set_rendered_name(cls, values: Dict[str, Any]) -> Dict[str, Any]: - """Set the :attr:`~.RenderedLayer.layer_name`` to the name of the rendered template directory.""" + """Set the [cookie_composer.layers.RenderedLayer.layer_name] to the name of the rendered template directory.""" if "rendered_name" in values: return values @@ -246,7 +248,7 @@ def render_layer( render_dir: Where to render the template full_context: The extra context from all layers in the composition commit: The commit to checkout if the template is a git repo - accept_hooks: Accept pre- and post-hooks if set to ``True`` + accept_hooks: Accept pre- and post-hooks if set to `True` Returns: The rendered layer information @@ -318,7 +320,7 @@ def get_layer_context( - initial context set in the template composition (or {} if not a composition or not set) - initial context passed in by user (as set from the command line. This is merged into the layer's inital context when the layer is deserialized. See - :func:`cookie_composer.io.get_composition_from_path_or_url`) + [cookie_composer.io.get_composition_from_path_or_url][]) - context from previous layers @@ -327,7 +329,7 @@ def get_layer_context( context_for_prompting: The raw context from the cookiecutter.json file with user defaults applied initial_context: The initial context from the layer configuration full_context: A full context from previous layers. - no_input: If ``False`` do not prompt for missing values and use defaults instead. + no_input: If `False` do not prompt for missing values and use defaults instead. Returns: A dict containing the context for rendering the layer @@ -350,10 +352,10 @@ def render_layers( Render layers to a destination. Args: - layers: A list of ``LayerConfig`` to render + layers: A list of `LayerConfig` to render destination: The location to merge the rendered layers to initial_context: An initial context to pass to the rendering - no_input: If ``True`` force each layer's ``no_input`` attribute to ``True`` + no_input: If `True` force each layer's `no_input` attribute to `True` accept_hooks: How to process pre/post hooks. Returns: diff --git a/cookie_composer/matching.py b/cookie_composer/matching.py index 3b894b7..5baa206 100644 --- a/cookie_composer/matching.py +++ b/cookie_composer/matching.py @@ -6,7 +6,7 @@ def rel_fnmatch(name: str, pat: str) -> bool: - """Force a relative match of the pattern by prefixing a ``*``.""" + """Force a relative match of the pattern by prefixing a `*`.""" return fnmatch(name, pat) if pat.startswith("*") else fnmatch(name, f"*{pat}") @@ -19,6 +19,6 @@ def matches_any_glob(path: Union[str, Path], patterns: List[str]) -> bool: patterns: A list of glob patterns Returns: - ``True`` if it matches any of the patterns + `True` if it matches any of the patterns """ return any(rel_fnmatch(str(path), pat) for pat in patterns) diff --git a/cookie_composer/merge_files/__init__.py b/cookie_composer/merge_files/__init__.py index 21ceaec..5dccefc 100644 --- a/cookie_composer/merge_files/__init__.py +++ b/cookie_composer/merge_files/__init__.py @@ -3,8 +3,6 @@ The merging functions should look similar to the following: -:: - def merge_generic_files(origin: Path, destination: Path, merge_strategy: str): ''' Merge two ??? files into one. @@ -20,7 +18,7 @@ def merge_generic_files(origin: Path, destination: Path, merge_strategy: str): The function must write the file to destination. -The function must wrap any errors into a :py:exc:`~cookie_composer.exceptions.MergeError` and raise it. +The function must wrap any errors into a [MergeError][cookie_composer.exceptions.MergeError] and raise it. """ from pathlib import Path diff --git a/cookie_composer/templates/source.py b/cookie_composer/templates/source.py index a271e53..6f90128 100644 --- a/cookie_composer/templates/source.py +++ b/cookie_composer/templates/source.py @@ -44,7 +44,7 @@ def get_template_repo( password: The password to use if template is a password-protected Zip archive. Returns: - A :class:`TemplateRepo` object. + A [TemplateRepo][cookie_composer.templates.types.TemplateRepo] object. """ user_config = get_user_config() tmpl_format, locality = identify_repo(url, local_path) diff --git a/cookie_composer/templates/types.py b/cookie_composer/templates/types.py index 0f5ce9d..3748319 100644 --- a/cookie_composer/templates/types.py +++ b/cookie_composer/templates/types.py @@ -72,10 +72,10 @@ def latest_sha(self) -> Optional[str]: """ Return the latest SHA of this template's repo. - If the template is not a git repository, it will always return ``None``. + If the template is not a git repository, it will always return `None`. Returns: - The latest hexsha of the template or ``None`` if the template isn't a git repo + The latest hexsha of the template or `None` if the template isn't a git repo """ from cookie_composer.git_commands import get_repo diff --git a/cookie_composer/utils.py b/cookie_composer/utils.py index 9ec82b1..fd03376 100644 --- a/cookie_composer/utils.py +++ b/cookie_composer/utils.py @@ -13,12 +13,12 @@ def echo( nl: bool = True, err: bool = False, color: Optional[bool] = None, - **styles, + **styles: Any, ) -> None: """ A local abstraction for printing messages. - Default behavior is that of ``click.secho`` . + Default behavior is that of [click.secho][]. This is to allow user feedback without every function requiring a click dependency. Especially during testing. @@ -64,13 +64,13 @@ def get_deleted_files(template_dir: Path, project_dir: Path) -> Set[Path]: def remove_paths(root: Path, paths_to_remove: Set[Path]) -> None: """ - Remove all paths in ``paths_to_remove`` from ``root``. + Remove all paths in `paths_to_remove` from `root`. Nabbed from Cruft: https://github.com/cruft/cruft/ Args: root: The absolute path of the directory requiring path removal - paths_to_remove: The set of relative paths to remove from ``root`` + paths_to_remove: The set of relative paths to remove from `root` """ # There is some redundancy here in chmod-ing dirs and/or files differently. abs_paths_to_remove = [root / path_to_remove for path_to_remove in paths_to_remove] diff --git a/mkdocs.yml b/mkdocs.yml index a4cec37..c9273fd 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -85,9 +85,11 @@ plugins: python: import: - https://docs.python.org/3/objects.inv - - https://numpy.org/doc/stable/objects.inv - - https://pandas.pydata.org/docs/objects.inv - - https://api.python.langchain.com/en/latest/objects.inv + - https://docs.pydantic.dev/latest/objects.inv + - https://jinja.palletsprojects.com/en/3.1.x/objects.inv + - https://cookiecutter.readthedocs.io/en/stable/objects.inv + - https://gitpython.readthedocs.io/en/stable/objects.inv + - https://click.palletsprojects.com/en/8.1.x/objects.inv options: allow_inspection: true docstring_style: google diff --git a/tests/fixtures/local_extension_template/local_extensions/main.py b/tests/fixtures/local_extension_template/local_extensions/main.py index 0088832..5029245 100644 --- a/tests/fixtures/local_extension_template/local_extensions/main.py +++ b/tests/fixtures/local_extension_template/local_extensions/main.py @@ -1,4 +1,4 @@ -"""Provides a custom extension, exposing a ``foobar`` filter.""" +"""Provides a custom extension, exposing a `foobar` filter.""" from cookiecutter.utils import simple_filter from jinja2.ext import Extension