diff --git a/src/usethis/_integrations/backend/uv/version.py b/src/usethis/_integrations/backend/uv/version.py index 410e060b..03c41924 100644 --- a/src/usethis/_integrations/backend/uv/version.py +++ b/src/usethis/_integrations/backend/uv/version.py @@ -3,7 +3,7 @@ from usethis._integrations.backend.uv.call import call_uv_subprocess from usethis._integrations.backend.uv.errors import UVSubprocessFailedError -FALLBACK_UV_VERSION = "0.9.20" +FALLBACK_UV_VERSION = "0.9.21" def get_uv_version() -> str: diff --git a/src/usethis/_integrations/ci/bitbucket/cache.py b/src/usethis/_integrations/ci/bitbucket/cache.py index 54f5a2f7..4489a41d 100644 --- a/src/usethis/_integrations/ci/bitbucket/cache.py +++ b/src/usethis/_integrations/ci/bitbucket/cache.py @@ -1,19 +1,14 @@ from __future__ import annotations -from typing import TYPE_CHECKING - from usethis._console import tick_print +from usethis._integrations.ci.bitbucket import schema from usethis._integrations.ci.bitbucket.init import ( ensure_bitbucket_pipelines_config_exists, ) -from usethis._integrations.ci.bitbucket.schema import Definitions from usethis._integrations.ci.bitbucket.yaml import BitbucketPipelinesYAMLManager -if TYPE_CHECKING: - from usethis._integrations.ci.bitbucket.schema import Cache, PipelinesConfiguration - -def get_cache_by_name() -> dict[str, Cache]: +def get_cache_by_name() -> dict[str, schema.Cache]: mgr = BitbucketPipelinesYAMLManager() config = mgr.model_validate() @@ -28,7 +23,7 @@ def get_cache_by_name() -> dict[str, Cache]: return cache_by_name -def add_caches(cache_by_name: dict[str, Cache]) -> None: +def add_caches(cache_by_name: dict[str, schema.Cache]) -> None: ensure_bitbucket_pipelines_config_exists() mgr = BitbucketPipelinesYAMLManager() @@ -38,10 +33,10 @@ def add_caches(cache_by_name: dict[str, Cache]) -> None: def _add_caches_via_model( - cache_by_name: dict[str, Cache], *, model: PipelinesConfiguration + cache_by_name: dict[str, schema.Cache], *, model: schema.PipelinesConfiguration ) -> None: if model.definitions is None: - model.definitions = Definitions() + model.definitions = schema.Definitions() if model.definitions.caches is None: model.definitions.caches = {} @@ -73,7 +68,7 @@ def remove_cache(cache: str) -> None: mgr.commit_model(model) -def _cache_exists(name: str, *, model: PipelinesConfiguration) -> bool: +def _cache_exists(name: str, *, model: schema.PipelinesConfiguration) -> bool: if model.definitions is None or model.definitions.caches is None: return False diff --git a/src/usethis/_integrations/ci/bitbucket/pipeweld.py b/src/usethis/_integrations/ci/bitbucket/pipeweld.py index 30def669..18736478 100644 --- a/src/usethis/_integrations/ci/bitbucket/pipeweld.py +++ b/src/usethis/_integrations/ci/bitbucket/pipeweld.py @@ -1,12 +1,12 @@ from __future__ import annotations from functools import singledispatch -from typing import TYPE_CHECKING from uuid import uuid4 from typing_extensions import assert_never import usethis._pipeweld.containers +from usethis._integrations.ci.bitbucket import schema from usethis._integrations.ci.bitbucket.errors import ( MissingStepError, UnexpectedImportPipelineError, @@ -14,43 +14,27 @@ from usethis._integrations.ci.bitbucket.init import ( ensure_bitbucket_pipelines_config_exists, ) -from usethis._integrations.ci.bitbucket.schema import ( - ImportPipeline, - Items, - Parallel, - ParallelExpanded, - ParallelItem, - ParallelSteps, - Pipeline, - Pipelines, - StageItem, - Step, - StepItem, -) from usethis._integrations.ci.bitbucket.schema_utils import step1tostep from usethis._integrations.ci.bitbucket.yaml import BitbucketPipelinesYAMLManager from usethis._pipeweld.ops import InsertParallel, InsertSuccessor, Instruction -if TYPE_CHECKING: - from usethis._integrations.ci.bitbucket.schema import PipelinesConfiguration - -def get_pipeweld_step(step: Step) -> str: +def get_pipeweld_step(step: schema.Step) -> str: if step.name is not None: return step.name return step.model_dump_json(exclude_defaults=True, by_alias=True) def get_pipeweld_pipeline_from_default( - model: PipelinesConfiguration, + model: schema.PipelinesConfiguration, ) -> usethis._pipeweld.containers.Series: if model.pipelines is None: - model.pipelines = Pipelines() + model.pipelines = schema.Pipelines() default = model.pipelines.default if default is None: items = [] - elif isinstance(default.root, ImportPipeline): + elif isinstance(default.root, schema.ImportPipeline): msg = ( "Cannot add step to default pipeline in 'bitbucket-pipelines.yml' because " "it is an import pipeline." @@ -66,7 +50,7 @@ def get_pipeweld_pipeline_from_default( @singledispatch def get_pipeweld_object( - item: StepItem | ParallelItem | StageItem, + item: schema.StepItem | schema.ParallelItem | schema.StageItem, ) -> ( str | usethis._pipeweld.containers.Parallel | usethis._pipeweld.containers.DepGroup ): @@ -74,18 +58,18 @@ def get_pipeweld_object( @get_pipeweld_object.register -def _(item: StepItem): +def _(item: schema.StepItem): return get_pipeweld_step(item.step) @get_pipeweld_object.register -def _(item: ParallelItem): +def _(item: schema.ParallelItem): parallel_steps: set[str] = set() if item.parallel is not None: - if isinstance(item.parallel.root, ParallelSteps): + if isinstance(item.parallel.root, schema.ParallelSteps): step_items = item.parallel.root.root - elif isinstance(item.parallel.root, ParallelExpanded): + elif isinstance(item.parallel.root, schema.ParallelExpanded): step_items = item.parallel.root.steps.root else: assert_never(item.parallel.root) @@ -97,7 +81,7 @@ def _(item: ParallelItem): @get_pipeweld_object.register -def _(item: StageItem): +def _(item: schema.StageItem): depgroup_steps: list[str] = [] if item.stage.name is not None: @@ -115,7 +99,7 @@ def _(item: StageItem): def apply_pipeweld_instruction( - instruction: Instruction, *, step_to_insert: Step + instruction: Instruction, *, step_to_insert: schema.Step ) -> None: ensure_bitbucket_pipelines_config_exists() @@ -130,18 +114,18 @@ def apply_pipeweld_instruction( def apply_pipeweld_instruction_via_model( instruction: Instruction, *, - step_to_insert: Step, - model: PipelinesConfiguration, + step_to_insert: schema.Step, + model: schema.PipelinesConfiguration, ) -> None: if model.pipelines is None: - model.pipelines = Pipelines() + model.pipelines = schema.Pipelines() pipelines = model.pipelines default = pipelines.default if default is None: items = [] - elif isinstance(default.root, ImportPipeline): + elif isinstance(default.root, schema.ImportPipeline): msg = ( f"Cannot add step '{step_to_insert.name}' to default pipeline in " f"'bitbucket-pipelines.yml' because it is an import pipeline." @@ -170,14 +154,14 @@ def apply_pipeweld_instruction_via_model( ) if default is None and items: - pipelines.default = Pipeline(Items(items)) + pipelines.default = schema.Pipeline(schema.Items(items)) def _apply_instruction_to_items( *, instruction: Instruction, - items: list[StepItem | ParallelItem | StageItem], - step_to_insert: Step, + items: list[schema.StepItem | schema.ParallelItem | schema.StageItem], + step_to_insert: schema.Step, ) -> None: """Apply an instruction to insert a step into the items list. @@ -188,14 +172,14 @@ def _apply_instruction_to_items( """ if instruction.after is None: # Insert at the beginning - always as a simple step - items.insert(0, StepItem(step=step_to_insert)) + items.insert(0, schema.StepItem(step=step_to_insert)) elif isinstance(instruction, InsertSuccessor): # Insert in series after the specified step for item in items: if _is_insertion_necessary(item, instruction=instruction): items.insert( items.index(item) + 1, - StepItem(step=step_to_insert), + schema.StepItem(step=step_to_insert), ) break elif isinstance(instruction, InsertParallel): @@ -211,8 +195,10 @@ def _apply_instruction_to_items( def _extract_step_from_items( - items: list[StepItem | ParallelItem | StageItem], *, step_name: str -) -> Step: + items: list[schema.StepItem | schema.ParallelItem | schema.StageItem], + *, + step_name: str, +) -> schema.Step: """Find and remove a step from the items list. This function searches for a step with the given name, removes it from the @@ -234,24 +220,24 @@ def _extract_step_from_items( @singledispatch def _extract_step_from_item( - item: StepItem | ParallelItem | StageItem, + item: schema.StepItem | schema.ParallelItem | schema.StageItem, *, step_name: str, - items: list[StepItem | ParallelItem | StageItem], + items: list[schema.StepItem | schema.ParallelItem | schema.StageItem], idx: int, -) -> Step | None: +) -> schema.Step | None: """Extract a step from an item, potentially modifying the items list.""" raise NotImplementedError @_extract_step_from_item.register def _( - item: StepItem, + item: schema.StepItem, *, step_name: str, - items: list[StepItem | ParallelItem | StageItem], + items: list[schema.StepItem | schema.ParallelItem | schema.StageItem], idx: int, -) -> Step | None: +) -> schema.Step | None: if get_pipeweld_step(item.step) == step_name: # Remove this item from the list items.pop(idx) @@ -261,16 +247,16 @@ def _( @_extract_step_from_item.register def _( - item: ParallelItem, + item: schema.ParallelItem, *, step_name: str, - items: list[StepItem | ParallelItem | StageItem], + items: list[schema.StepItem | schema.ParallelItem | schema.StageItem], idx: int, -) -> Step | None: +) -> schema.Step | None: if item.parallel is not None: - if isinstance(item.parallel.root, ParallelSteps): + if isinstance(item.parallel.root, schema.ParallelSteps): step_items = item.parallel.root.root - elif isinstance(item.parallel.root, ParallelExpanded): + elif isinstance(item.parallel.root, schema.ParallelExpanded): step_items = item.parallel.root.steps.root else: assert_never(item.parallel.root) @@ -295,12 +281,12 @@ def _( @_extract_step_from_item.register def _( # https://github.com/astral-sh/ruff/issues/18654 - item: StageItem, # noqa: ARG001 + item: schema.StageItem, # noqa: ARG001 *, step_name: str, # noqa: ARG001 - items: list[StepItem | ParallelItem | StageItem], # noqa: ARG001 + items: list[schema.StepItem | schema.ParallelItem | schema.StageItem], # noqa: ARG001 idx: int, # noqa: ARG001 -) -> Step | None: +) -> schema.Step | None: # We don't extract steps from within stages as they represent deployment # stages and their internal structure should be preserved. return None @@ -308,11 +294,11 @@ def _( @singledispatch def _insert_parallel_step( - item: StepItem | ParallelItem | StageItem, + item: schema.StepItem | schema.ParallelItem | schema.StageItem, *, - items: list[StepItem | ParallelItem | StageItem], + items: list[schema.StepItem | schema.ParallelItem | schema.StageItem], idx: int, - step_to_insert: Step, + step_to_insert: schema.Step, ) -> None: """Insert a step in parallel with an existing item. @@ -324,19 +310,19 @@ def _insert_parallel_step( @_insert_parallel_step.register def _( - item: StepItem, + item: schema.StepItem, *, - items: list[StepItem | ParallelItem | StageItem], + items: list[schema.StepItem | schema.ParallelItem | schema.StageItem], idx: int, - step_to_insert: Step, + step_to_insert: schema.Step, ) -> None: # Replace the single step with a parallel block containing both steps - parallel_item = ParallelItem( - parallel=Parallel( - ParallelSteps( + parallel_item = schema.ParallelItem( + parallel=schema.Parallel( + schema.ParallelSteps( [ - StepItem(step=item.step), - StepItem(step=step_to_insert), + schema.StepItem(step=item.step), + schema.StepItem(step=step_to_insert), ] ) ) @@ -346,31 +332,31 @@ def _( @_insert_parallel_step.register def _( - item: ParallelItem, + item: schema.ParallelItem, *, # https://github.com/astral-sh/ruff/issues/18654 - items: list[StepItem | ParallelItem | StageItem], # noqa: ARG001 + items: list[schema.StepItem | schema.ParallelItem | schema.StageItem], # noqa: ARG001 idx: int, # noqa: ARG001 - step_to_insert: Step, + step_to_insert: schema.Step, ) -> None: if item.parallel is not None: - if isinstance(item.parallel.root, ParallelSteps): + if isinstance(item.parallel.root, schema.ParallelSteps): # Add to the existing list of parallel steps - item.parallel.root.root.append(StepItem(step=step_to_insert)) - elif isinstance(item.parallel.root, ParallelExpanded): + item.parallel.root.root.append(schema.StepItem(step=step_to_insert)) + elif isinstance(item.parallel.root, schema.ParallelExpanded): # Add to the expanded parallel steps - item.parallel.root.steps.root.append(StepItem(step=step_to_insert)) + item.parallel.root.steps.root.append(schema.StepItem(step=step_to_insert)) else: assert_never(item.parallel.root) @_insert_parallel_step.register def _( - item: StageItem, + item: schema.StageItem, *, - items: list[StepItem | ParallelItem | StageItem], + items: list[schema.StepItem | schema.ParallelItem | schema.StageItem], idx: int, - step_to_insert: Step, + step_to_insert: schema.Step, ) -> None: # StageItems are trickier since they aren't supported in ParallelSteps. But we # never need to add them in practice anyway. The only reason this is really here @@ -380,7 +366,7 @@ def _( @singledispatch def _is_insertion_necessary( - item: StepItem | ParallelItem | StageItem, + item: schema.StepItem | schema.ParallelItem | schema.StageItem, *, instruction: Instruction, ) -> bool: @@ -388,16 +374,16 @@ def _is_insertion_necessary( @_is_insertion_necessary.register -def _(item: StepItem, *, instruction: Instruction): +def _(item: schema.StepItem, *, instruction: Instruction): return get_pipeweld_step(item.step) == instruction.after @_is_insertion_necessary.register -def _(item: ParallelItem, *, instruction: Instruction): +def _(item: schema.ParallelItem, *, instruction: Instruction): if item.parallel is not None: - if isinstance(item.parallel.root, ParallelSteps): + if isinstance(item.parallel.root, schema.ParallelSteps): step_items = item.parallel.root.root - elif isinstance(item.parallel.root, ParallelExpanded): + elif isinstance(item.parallel.root, schema.ParallelExpanded): step_items = item.parallel.root.steps.root else: assert_never(item.parallel.root) @@ -409,7 +395,7 @@ def _(item: ParallelItem, *, instruction: Instruction): @_is_insertion_necessary.register -def _(item: StageItem, *, instruction: Instruction): +def _(item: schema.StageItem, *, instruction: Instruction): step1s = item.stage.steps.copy() for step1 in step1s: diff --git a/src/usethis/_integrations/ci/bitbucket/schema_utils.py b/src/usethis/_integrations/ci/bitbucket/schema_utils.py index 1bf86ca1..8de99587 100644 --- a/src/usethis/_integrations/ci/bitbucket/schema_utils.py +++ b/src/usethis/_integrations/ci/bitbucket/schema_utils.py @@ -1,14 +1,9 @@ from __future__ import annotations -from typing import TYPE_CHECKING +from usethis._integrations.ci.bitbucket import schema -from usethis._integrations.ci.bitbucket.schema import Step -if TYPE_CHECKING: - from usethis._integrations.ci.bitbucket.schema import Step1 - - -def step1tostep(step1: Step1) -> Step: +def step1tostep(step1: schema.Step1) -> schema.Step: """Promoting Step1 to a standard Step. This is necessary because there is some unusual inconsistency in the JSON Schema @@ -19,5 +14,5 @@ def step1tostep(step1: Step1) -> Step: """ step2 = step1.step - step = Step(**step2.model_dump(by_alias=True)) + step = schema.Step(**step2.model_dump(by_alias=True)) return step diff --git a/src/usethis/_integrations/ci/bitbucket/steps.py b/src/usethis/_integrations/ci/bitbucket/steps.py index 5622e8b1..022f13a8 100644 --- a/src/usethis/_integrations/ci/bitbucket/steps.py +++ b/src/usethis/_integrations/ci/bitbucket/steps.py @@ -11,6 +11,7 @@ from usethis._config import usethis_config from usethis._console import instruct_print, tick_print from usethis._integrations.backend.dispatch import get_backend +from usethis._integrations.ci.bitbucket import schema from usethis._integrations.ci.bitbucket.anchor import ( ScriptItemAnchor, anchor_name_from_script_item, @@ -27,19 +28,6 @@ get_pipeweld_pipeline_from_default, get_pipeweld_step, ) -from usethis._integrations.ci.bitbucket.schema import ( - CachePath, - Definitions, - ImportPipeline, - Parallel, - ParallelExpanded, - ParallelItem, - ParallelSteps, - Script, - StageItem, - Step, - StepItem, -) from usethis._integrations.ci.bitbucket.schema_utils import step1tostep from usethis._integrations.ci.bitbucket.yaml import BitbucketPipelinesYAMLManager from usethis._integrations.environ.python import get_supported_minor_python_versions @@ -49,16 +37,12 @@ from ruamel.yaml.anchor import Anchor from usethis._integrations.ci.bitbucket.anchor import ScriptItemName - from usethis._integrations.ci.bitbucket.schema import ( - Pipeline, - PipelinesConfiguration, - ) from usethis._integrations.file.yaml.io_ import YAMLDocument _CACHE_LOOKUP = { - "uv": CachePath("~/.cache/uv"), - "pre-commit": CachePath("~/.cache/pre-commit"), + "uv": schema.CachePath("~/.cache/uv"), + "pre-commit": schema.CachePath("~/.cache/pre-commit"), } @@ -80,7 +64,7 @@ script_item.yaml_set_anchor(value=name, always_dump=True) -def add_bitbucket_step_in_default(step: Step) -> None: +def add_bitbucket_step_in_default(step: schema.Step) -> None: ensure_bitbucket_pipelines_config_exists() try: @@ -112,8 +96,11 @@ def add_bitbucket_step_in_default(step: Step) -> None: def _add_step_in_default_via_model( - step: Step, *, model: PipelinesConfiguration, doc: YAMLDocument -) -> PipelinesConfiguration: + step: schema.Step, + *, + model: schema.PipelinesConfiguration, + doc: YAMLDocument, +) -> schema.PipelinesConfiguration: _add_step_caches_via_model(step, model=model) if step.name != _PLACEHOLDER_NAME: @@ -173,8 +160,11 @@ def _add_step_in_default_via_model( def _resolve_script_anchors( - step: Step, *, model: PipelinesConfiguration, doc: YAMLDocument -) -> Step: + step: schema.Step, + *, + model: schema.PipelinesConfiguration, + doc: YAMLDocument, +) -> schema.Step: """Resolve script item anchors by adding definitions and replacing with references.""" # Process each script item in the step for idx, script_item in enumerate(step.script.root): @@ -202,7 +192,7 @@ def _resolve_script_anchors( def _add_script_item_definition( *, script_item_name: ScriptItemName, - model: PipelinesConfiguration, + model: schema.PipelinesConfiguration, doc: YAMLDocument, ) -> None: """Add a script item definition to the YAML file's definitions section. @@ -232,7 +222,7 @@ def _add_script_item_definition( if "definitions" not in content: content["definitions"] = {} if model.definitions is None: - model.definitions = Definitions() + model.definitions = schema.Definitions() if "script_items" not in content["definitions"]: content["definitions"]["script_items"] = CommentedSeq() @@ -254,7 +244,7 @@ def _add_script_item_definition( def _get_script_item_insertion_index( - *, script_item_name: ScriptItemName, model: PipelinesConfiguration + *, script_item_name: ScriptItemName, model: schema.PipelinesConfiguration ) -> int: """Get the correct insertion index for a script item to maintain canonical order.""" # Check if we have existing script items in the model @@ -277,7 +267,7 @@ def _get_script_item_insertion_index( return len(existing_script_items) # Default to end -def remove_bitbucket_step_from_default(step: Step) -> None: +def remove_bitbucket_step_from_default(step: schema.Step) -> None: """Remove a step from the default pipeline in the Bitbucket Pipelines configuration. If the default pipeline does not exist, or the step is not found, nothing happens. @@ -305,7 +295,7 @@ def remove_bitbucket_step_from_default(step: Step) -> None: pipeline = model.pipelines.default - if isinstance(pipeline.root, ImportPipeline): + if isinstance(pipeline.root, schema.ImportPipeline): msg = "Cannot remove steps from an import pipeline." raise UnexpectedImportPipelineError(msg) @@ -313,7 +303,7 @@ def remove_bitbucket_step_from_default(step: Step) -> None: # Iterate over the items. Any item that contains the step is censored to remove # references to the step. If the only thing in the item is the step, we get None - new_items: list[StepItem | ParallelItem | StageItem] = [] + new_items: list[schema.StepItem | schema.ParallelItem | schema.StageItem] = [] for item in items: new_item = _censor_step(item, step=step) if new_item is not None: @@ -334,31 +324,35 @@ def remove_bitbucket_step_from_default(step: Step) -> None: @singledispatch def _censor_step( - item: StepItem | ParallelItem | StageItem, *, step: Step -) -> StepItem | ParallelItem | StageItem | None: + item: schema.StepItem | schema.ParallelItem | schema.StageItem, *, step: schema.Step +) -> schema.StepItem | schema.ParallelItem | schema.StageItem | None: """Censor a step from a pipeline item, with None if necessary.""" raise NotImplementedError -@_censor_step.register(StepItem) -def _(item: StepItem, *, step: Step) -> StepItem | ParallelItem | StageItem | None: +@_censor_step.register(schema.StepItem) +def _( + item: schema.StepItem, *, step: schema.Step +) -> schema.StepItem | schema.ParallelItem | schema.StageItem | None: if bitbucket_steps_are_equivalent(item.step, step): return None return item -@_censor_step.register(ParallelItem) -def _(item: ParallelItem, *, step: Step) -> StepItem | ParallelItem | StageItem | None: +@_censor_step.register(schema.ParallelItem) +def _( + item: schema.ParallelItem, *, step: schema.Step +) -> schema.StepItem | schema.ParallelItem | schema.StageItem | None: par = item.parallel.root - if isinstance(par, ParallelSteps): + if isinstance(par, schema.ParallelSteps): step_items = par.root - elif isinstance(par, ParallelExpanded): + elif isinstance(par, schema.ParallelExpanded): step_items = par.steps.root else: assert_never(par) - new_step_items: list[StepItem] = [] + new_step_items: list[schema.StepItem] = [] for step_item in step_items: if bitbucket_steps_are_equivalent(step_item.step, step): continue @@ -368,17 +362,21 @@ def _(item: ParallelItem, *, step: Step) -> StepItem | ParallelItem | StageItem return None elif len(new_step_items) == 1 and len(step_items) != 1: return new_step_items[0] - elif isinstance(par, ParallelSteps): - return ParallelItem(parallel=Parallel(ParallelSteps(new_step_items))) - elif isinstance(par, ParallelExpanded): - par.steps = ParallelSteps(new_step_items) - return ParallelItem(parallel=Parallel(par)) + elif isinstance(par, schema.ParallelSteps): + return schema.ParallelItem( + parallel=schema.Parallel(schema.ParallelSteps(new_step_items)) + ) + elif isinstance(par, schema.ParallelExpanded): + par.steps = schema.ParallelSteps(new_step_items) + return schema.ParallelItem(parallel=schema.Parallel(par)) else: assert_never(par) -@_censor_step.register(StageItem) -def _(item: StageItem, *, step: Step) -> StepItem | ParallelItem | StageItem | None: +@_censor_step.register(schema.StageItem) +def _( + item: schema.StageItem, *, step: schema.Step +) -> schema.StepItem | schema.ParallelItem | schema.StageItem | None: step1s = item.stage.steps new_step1s = [] @@ -392,7 +390,7 @@ def _(item: StageItem, *, step: Step) -> StepItem | ParallelItem | StageItem | N new_stage = item.stage.model_copy() new_stage.steps = new_step1s - return StageItem(stage=new_stage) + return schema.StageItem(stage=new_stage) def is_cache_used(cache: str) -> bool: @@ -403,7 +401,9 @@ def is_cache_used(cache: str) -> bool: return False -def _add_step_caches_via_model(step: Step, *, model: PipelinesConfiguration) -> None: +def _add_step_caches_via_model( + step: schema.Step, *, model: schema.PipelinesConfiguration +) -> None: if step.caches is not None: cache_by_name = {} for name in step.caches: @@ -419,7 +419,9 @@ def _add_step_caches_via_model(step: Step, *, model: PipelinesConfiguration) -> _add_caches_via_model(cache_by_name, model=model) -def bitbucket_steps_are_equivalent(step1: Step | None, step2: Step) -> bool: +def bitbucket_steps_are_equivalent( + step1: schema.Step | None, step2: schema.Step +) -> bool: if step1 is None: return False @@ -441,7 +443,7 @@ def bitbucket_steps_are_equivalent(step1: Step | None, step2: Step) -> bool: return step1 == step2 -def get_steps_in_default() -> list[Step]: +def get_steps_in_default() -> list[schema.Step]: """Get the steps in the default pipeline of the Bitbucket Pipelines configuration. If the default pipeline does not exist, an empty list is returned. @@ -469,8 +471,8 @@ def get_steps_in_default() -> list[Step]: return _get_steps_in_pipeline(pipeline) -def _get_steps_in_pipeline(pipeline: Pipeline) -> list[Step]: - if isinstance(pipeline.root, ImportPipeline): +def _get_steps_in_pipeline(pipeline: schema.Pipeline) -> list[schema.Step]: + if isinstance(pipeline.root, schema.ImportPipeline): msg = "Cannot retrieve steps from an import pipeline." raise UnexpectedImportPipelineError(msg) @@ -484,21 +486,21 @@ def _get_steps_in_pipeline(pipeline: Pipeline) -> list[Step]: @singledispatch -def get_steps_in_pipeline_item(item) -> list[Step]: +def get_steps_in_pipeline_item(item) -> list[schema.Step]: raise NotImplementedError -@get_steps_in_pipeline_item.register(StepItem) -def _(item: StepItem) -> list[Step]: +@get_steps_in_pipeline_item.register(schema.StepItem) +def _(item: schema.StepItem) -> list[schema.Step]: return [item.step] -@get_steps_in_pipeline_item.register(ParallelItem) -def _(item: ParallelItem) -> list[Step]: +@get_steps_in_pipeline_item.register(schema.ParallelItem) +def _(item: schema.ParallelItem) -> list[schema.Step]: _p = item.parallel.root - if isinstance(_p, ParallelSteps): + if isinstance(_p, schema.ParallelSteps): step_items = _p.root - elif isinstance(_p, ParallelExpanded): + elif isinstance(_p, schema.ParallelExpanded): step_items = _p.steps.root else: assert_never(_p) @@ -507,8 +509,8 @@ def _(item: ParallelItem) -> list[Step]: return steps -@get_steps_in_pipeline_item.register(StageItem) -def _(item: StageItem) -> list[Step]: +@get_steps_in_pipeline_item.register(schema.StageItem) +def _(item: schema.StageItem) -> list[schema.Step]: return [step1tostep(step1) for step1 in item.stage.steps if step1.step is not None] @@ -528,13 +530,13 @@ def add_placeholder_step_in_default(report_placeholder: bool = True) -> None: ) -def _get_placeholder_step() -> Step: +def _get_placeholder_step() -> schema.Step: backend = get_backend() if backend is BackendEnum.uv: - return Step( + return schema.Step( name=_PLACEHOLDER_NAME, - script=Script( + script=schema.Script( [ ScriptItemAnchor(name="install-uv"), "echo 'Hello, world!'", @@ -543,9 +545,9 @@ def _get_placeholder_step() -> Step: caches=["uv"], ) elif backend is BackendEnum.none: - return Step( + return schema.Step( name=_PLACEHOLDER_NAME, - script=Script( + script=schema.Script( [ "echo 'Hello, world!'", ] @@ -556,7 +558,7 @@ def _get_placeholder_step() -> Step: def get_defined_script_items( - *, model: PipelinesConfiguration, doc: YAMLDocument + *, model: schema.PipelinesConfiguration, doc: YAMLDocument ) -> dict[str, str]: """Get defined script items with their anchor names. diff --git a/src/usethis/_integrations/ci/bitbucket/yaml.py b/src/usethis/_integrations/ci/bitbucket/yaml.py index e618c3fa..4fa18339 100644 --- a/src/usethis/_integrations/ci/bitbucket/yaml.py +++ b/src/usethis/_integrations/ci/bitbucket/yaml.py @@ -5,13 +5,8 @@ from pydantic import ValidationError +from usethis._integrations.ci.bitbucket import schema from usethis._integrations.ci.bitbucket.errors import BitbucketPipelinesYAMLSchemaError -from usethis._integrations.ci.bitbucket.schema import ( - PipelinesConfiguration, - Step, - Step2, - StepBase, -) from usethis._integrations.file.yaml.io_ import YAMLFileManager from usethis._integrations.file.yaml.update import update_ruamel_yaml_map from usethis._integrations.pydantic.dump import fancy_model_dump @@ -22,10 +17,10 @@ from usethis._integrations.pydantic.dump import ModelRepresentation ORDER_BY_CLS: dict[type[BaseModel], list[str]] = { - PipelinesConfiguration: ["image", "clone", "definitions"], - StepBase: ["name", "caches", "script"], - Step: ["name", "caches", "script"], - Step2: ["name", "caches", "script"], + schema.PipelinesConfiguration: ["image", "clone", "definitions"], + schema.StepBase: ["name", "caches", "script"], + schema.Step: ["name", "caches", "script"], + schema.Step2: ["name", "caches", "script"], } @@ -36,7 +31,7 @@ class BitbucketPipelinesYAMLManager(YAMLFileManager): def relative_path(self) -> Path: return Path("bitbucket-pipelines.yml") - def model_validate(self) -> PipelinesConfiguration: + def model_validate(self) -> schema.PipelinesConfiguration: """Validate the current document content against the JSON schema. Returns: @@ -47,12 +42,12 @@ def model_validate(self) -> PipelinesConfiguration: """ doc = self.get() try: - return PipelinesConfiguration.model_validate(doc.content) + return schema.PipelinesConfiguration.model_validate(doc.content) except ValidationError as err: msg = f"Invalid 'bitbucket-pipelines.yml' file:\n{err}" raise BitbucketPipelinesYAMLSchemaError(msg) from None - def commit_model(self, model: PipelinesConfiguration) -> None: + def commit_model(self, model: schema.PipelinesConfiguration) -> None: doc = self.get() # Special handling for script_items: These items may contain YAML anchors (e.g., @@ -128,7 +123,9 @@ def commit_model(self, model: PipelinesConfiguration) -> None: def _bitbucket_fancy_dump( - config: PipelinesConfiguration, *, reference: ModelRepresentation | None = None + config: schema.PipelinesConfiguration, + *, + reference: ModelRepresentation | None = None, ) -> dict[str, ModelRepresentation]: dump = fancy_model_dump(config, reference=reference, order_by_cls=ORDER_BY_CLS) diff --git a/src/usethis/_integrations/pre_commit/hooks.py b/src/usethis/_integrations/pre_commit/hooks.py index 635ba5a3..eb7a8ea6 100644 --- a/src/usethis/_integrations/pre_commit/hooks.py +++ b/src/usethis/_integrations/pre_commit/hooks.py @@ -4,25 +4,16 @@ from usethis._config import usethis_config from usethis._console import instruct_print, tick_print +from usethis._integrations.pre_commit import schema from usethis._integrations.pre_commit.init import ( ensure_pre_commit_config_exists, ) from usethis._integrations.pre_commit.language import get_system_language -from usethis._integrations.pre_commit.schema import ( - HookDefinition, - LocalRepo, - MetaRepo, -) from usethis._integrations.pre_commit.yaml import PreCommitConfigYAMLManager if TYPE_CHECKING: from collections.abc import Collection - from usethis._integrations.pre_commit.schema import ( - JsonSchemaForPreCommitConfigYaml, - UriRepo, - ) - _HOOK_ORDER = [ "sync-with-uv", "validate-pyproject", @@ -40,7 +31,7 @@ _PLACEHOLDER_ID = "placeholder" -def add_repo(repo: LocalRepo | UriRepo) -> None: +def add_repo(repo: schema.LocalRepo | schema.UriRepo) -> None: """Add a pre-commit repo configuration to the pre-commit configuration file. This assumes the hook doesn't already exist in the configuration file. @@ -113,10 +104,10 @@ def add_repo(repo: LocalRepo | UriRepo) -> None: def insert_repo( *, - repo_to_insert: LocalRepo | UriRepo | MetaRepo, - existing_repos: Collection[LocalRepo | UriRepo | MetaRepo], + repo_to_insert: schema.LocalRepo | schema.UriRepo | schema.MetaRepo, + existing_repos: Collection[schema.LocalRepo | schema.UriRepo | schema.MetaRepo], predecessor: str | None, -) -> list[LocalRepo | UriRepo | MetaRepo]: +) -> list[schema.LocalRepo | schema.UriRepo | schema.MetaRepo]: # Insert the new hook after the last precedent repo # Do this by iterating over the repos and hooks, and inserting the new hook # after the last precedent @@ -161,7 +152,9 @@ def insert_repo( return repos -def _report_adding_repo(repo: LocalRepo | UriRepo | MetaRepo) -> None: +def _report_adding_repo( + repo: schema.LocalRepo | schema.UriRepo | schema.MetaRepo, +) -> None: """Append a repo to the end of the existing repos with message.""" if repo.hooks is not None: for inserted_hook in repo.hooks: @@ -179,11 +172,11 @@ def add_placeholder_hook() -> None: ) -def _get_placeholder_repo_config() -> LocalRepo: - return LocalRepo( +def _get_placeholder_repo_config() -> schema.LocalRepo: + return schema.LocalRepo( repo="local", hooks=[ - HookDefinition( + schema.HookDefinition( id=_PLACEHOLDER_ID, name="Placeholder - add your own hooks!", entry="""uv run --isolated --frozen --offline python -c "print('hello world!')\"""", @@ -206,7 +199,7 @@ def remove_hook(hook_id: str) -> None: # search across the repos for any hooks with matching ID for repo in model.repos: - if isinstance(repo, MetaRepo) or repo.hooks is None: + if isinstance(repo, schema.MetaRepo) or repo.hooks is None: continue for hook in repo.hooks: @@ -236,7 +229,9 @@ def get_hook_ids() -> list[str]: return extract_hook_ids(model) -def extract_hook_ids(model: JsonSchemaForPreCommitConfigYaml) -> list[str]: +def extract_hook_ids( + model: schema.JsonSchemaForPreCommitConfigYaml, +) -> list[str]: hook_ids = [] for repo in model.repos: if repo.hooks is None: @@ -248,7 +243,9 @@ def extract_hook_ids(model: JsonSchemaForPreCommitConfigYaml) -> list[str]: return hook_ids -def hooks_are_equivalent(hook: HookDefinition, other: HookDefinition) -> bool: +def hooks_are_equivalent( + hook: schema.HookDefinition, other: schema.HookDefinition +) -> bool: """Check if two hooks are equivalent.""" if hook_ids_are_equivalent(hook.id, other.id): return True diff --git a/src/usethis/_integrations/pre_commit/language.py b/src/usethis/_integrations/pre_commit/language.py index 6b403b83..9a66b80e 100644 --- a/src/usethis/_integrations/pre_commit/language.py +++ b/src/usethis/_integrations/pre_commit/language.py @@ -1,10 +1,10 @@ from packaging.version import Version -from usethis._integrations.pre_commit.schema import Language +from usethis._integrations.pre_commit import schema from usethis._integrations.pre_commit.version import get_minimum_pre_commit_version -def get_system_language() -> Language: +def get_system_language() -> schema.Language: """Get the appropriate 'system' language keyword based on pre-commit version. Returns 'unsupported' for pre-commit >= 4.4.0, otherwise 'system'. @@ -15,5 +15,5 @@ def get_system_language() -> Language: """ min_version = get_minimum_pre_commit_version() if min_version is not None and Version(min_version) >= Version("4.4.0"): - return Language("unsupported") - return Language("system") + return schema.Language("unsupported") + return schema.Language("system") diff --git a/src/usethis/_integrations/pre_commit/yaml.py b/src/usethis/_integrations/pre_commit/yaml.py index 858a5a24..a81fcbe7 100644 --- a/src/usethis/_integrations/pre_commit/yaml.py +++ b/src/usethis/_integrations/pre_commit/yaml.py @@ -8,8 +8,8 @@ from usethis._integrations.file.yaml.io_ import YAMLFileManager from usethis._integrations.file.yaml.update import update_ruamel_yaml_map +from usethis._integrations.pre_commit import schema from usethis._integrations.pre_commit.errors import PreCommitConfigYAMLConfigError -from usethis._integrations.pre_commit.schema import JsonSchemaForPreCommitConfigYaml from usethis._integrations.pydantic.dump import fancy_model_dump if TYPE_CHECKING: @@ -27,7 +27,7 @@ class PreCommitConfigYAMLManager(YAMLFileManager): def relative_path(self) -> Path: return Path(".pre-commit-config.yaml") - def model_validate(self) -> JsonSchemaForPreCommitConfigYaml: + def model_validate(self) -> schema.JsonSchemaForPreCommitConfigYaml: """Validate the current document content against the JSON schema. Returns: @@ -43,12 +43,14 @@ def model_validate(self) -> JsonSchemaForPreCommitConfigYaml: ruamel_content = CommentedMap({"repos": []}) try: - return JsonSchemaForPreCommitConfigYaml.model_validate(ruamel_content) + return schema.JsonSchemaForPreCommitConfigYaml.model_validate( + ruamel_content + ) except ValidationError as err: msg = f"Invalid '.pre-commit-config.yaml' file:\n{err}" raise PreCommitConfigYAMLConfigError(msg) from None - def commit_model(self, model: JsonSchemaForPreCommitConfigYaml) -> None: + def commit_model(self, model: schema.JsonSchemaForPreCommitConfigYaml) -> None: doc = self.get() dump = _pre_commit_fancy_dump(model, reference=doc.content) update_ruamel_yaml_map(doc.content, dump, preserve_comments=True) @@ -57,7 +59,7 @@ def commit_model(self, model: JsonSchemaForPreCommitConfigYaml) -> None: def _pre_commit_fancy_dump( - config: JsonSchemaForPreCommitConfigYaml, *, reference: ModelRepresentation + config: schema.JsonSchemaForPreCommitConfigYaml, *, reference: ModelRepresentation ) -> dict[str, ModelRepresentation]: dump = fancy_model_dump(config, reference=reference, order_by_cls=ORDER_BY_CLS) diff --git a/src/usethis/_tool/base.py b/src/usethis/_tool/base.py index c243f97c..aebcd18b 100644 --- a/src/usethis/_tool/base.py +++ b/src/usethis/_tool/base.py @@ -9,11 +9,10 @@ from usethis._console import tick_print, warn_print from usethis._deps import add_deps_to_group, is_dep_in_any_group, remove_deps_from_group from usethis._integrations.backend.dispatch import get_backend +from usethis._integrations.ci.bitbucket import schema as bitbucket_schema from usethis._integrations.ci.bitbucket.anchor import ( ScriptItemAnchor as BitbucketScriptItemAnchor, ) -from usethis._integrations.ci.bitbucket.schema import Script as BitbucketScript -from usethis._integrations.ci.bitbucket.schema import Step as BitbucketStep from usethis._integrations.ci.bitbucket.steps import ( add_bitbucket_step_in_default, bitbucket_steps_are_equivalent, @@ -38,7 +37,7 @@ from pathlib import Path from usethis._integrations.backend.uv.deps import Dependency - from usethis._integrations.pre_commit.schema import LocalRepo, UriRepo + from usethis._integrations.pre_commit import schema as pre_commit_schema from usethis._io import KeyValueFileManager from usethis._tool.config import ConfigItem, ResolutionT from usethis._tool.rule import Rule @@ -220,7 +219,9 @@ def add_doc_deps(self) -> None: def remove_doc_deps(self) -> None: remove_deps_from_group(self.get_doc_deps(unconditional=True), "doc") - def get_pre_commit_repos(self) -> list[LocalRepo | UriRepo]: + def get_pre_commit_repos( + self, + ) -> list[pre_commit_schema.LocalRepo | pre_commit_schema.UriRepo]: """Get the pre-commit repository definitions for the tool.""" return [c.repo for c in self.get_pre_commit_config().repo_configs] @@ -589,7 +590,9 @@ def get_install_method(self) -> Literal["pre-commit", "devdep"] | None: return "pre-commit" return None - def get_bitbucket_steps(self, *, matrix_python: bool = True) -> list[BitbucketStep]: + def get_bitbucket_steps( + self, *, matrix_python: bool = True + ) -> list[bitbucket_schema.Step]: """Get the Bitbucket pipeline step associated with this tool. By default, this creates a single step using the tool's default_command(). @@ -608,10 +611,10 @@ def get_bitbucket_steps(self, *, matrix_python: bool = True) -> list[BitbucketSt backend = get_backend() if backend is BackendEnum.uv: return [ - BitbucketStep( + bitbucket_schema.Step( name=f"Run {self.name}", caches=["uv"], - script=BitbucketScript( + script=bitbucket_schema.Script( [ BitbucketScriptItemAnchor(name="install-uv"), cmd, @@ -621,9 +624,9 @@ def get_bitbucket_steps(self, *, matrix_python: bool = True) -> list[BitbucketSt ] elif backend is BackendEnum.none: return [ - BitbucketStep( + bitbucket_schema.Step( name=f"Run {self.name}", - script=BitbucketScript( + script=bitbucket_schema.Script( [ BitbucketScriptItemAnchor(name="ensure-venv"), cmd, diff --git a/src/usethis/_tool/impl/codespell.py b/src/usethis/_tool/impl/codespell.py index c69f4ea0..c0cc8e47 100644 --- a/src/usethis/_tool/impl/codespell.py +++ b/src/usethis/_tool/impl/codespell.py @@ -12,7 +12,7 @@ from usethis._integrations.backend.uv.used import is_uv_used from usethis._integrations.file.pyproject_toml.io_ import PyprojectTOMLManager from usethis._integrations.file.setup_cfg.io_ import SetupCFGManager -from usethis._integrations.pre_commit.schema import HookDefinition, UriRepo +from usethis._integrations.pre_commit import schema as pre_commit_schema from usethis._tool.base import Tool from usethis._tool.config import ConfigEntry, ConfigItem, ConfigSpec from usethis._tool.pre_commit import PreCommitConfig @@ -129,11 +129,13 @@ def get_managed_files(self) -> list[Path]: def get_pre_commit_config(self) -> PreCommitConfig: return PreCommitConfig.from_single_repo( - UriRepo( + pre_commit_schema.UriRepo( repo="https://github.com/codespell-project/codespell", rev=_CODESPELL_VERSION, hooks=[ - HookDefinition(id="codespell", additional_dependencies=["tomli"]) + pre_commit_schema.HookDefinition( + id="codespell", additional_dependencies=["tomli"] + ) ], ), requires_venv=False, diff --git a/src/usethis/_tool/impl/deptry.py b/src/usethis/_tool/impl/deptry.py index fdadd8fd..5ab79950 100644 --- a/src/usethis/_tool/impl/deptry.py +++ b/src/usethis/_tool/impl/deptry.py @@ -9,8 +9,8 @@ from usethis._integrations.backend.dispatch import get_backend from usethis._integrations.backend.uv.used import is_uv_used from usethis._integrations.file.pyproject_toml.io_ import PyprojectTOMLManager +from usethis._integrations.pre_commit import schema as pre_commit_schema from usethis._integrations.pre_commit.language import get_system_language -from usethis._integrations.pre_commit.schema import HookDefinition, LocalRepo from usethis._integrations.project.layout import get_source_dir_str from usethis._tool.base import Tool from usethis._tool.config import ( @@ -96,10 +96,10 @@ def get_pre_commit_config(self) -> PreCommitConfig: _dir = get_source_dir_str() if backend is BackendEnum.uv: return PreCommitConfig.from_single_repo( - LocalRepo( + pre_commit_schema.LocalRepo( repo="local", hooks=[ - HookDefinition( + pre_commit_schema.HookDefinition( id="deptry", name="deptry", entry=f"uv run --frozen --offline deptry {_dir}", @@ -114,10 +114,10 @@ def get_pre_commit_config(self) -> PreCommitConfig: ) elif backend is BackendEnum.none: return PreCommitConfig.from_single_repo( - LocalRepo( + pre_commit_schema.LocalRepo( repo="local", hooks=[ - HookDefinition( + pre_commit_schema.HookDefinition( id="deptry", name="deptry", entry=f"deptry {_dir}", diff --git a/src/usethis/_tool/impl/import_linter.py b/src/usethis/_tool/impl/import_linter.py index d4adb261..066adc06 100644 --- a/src/usethis/_tool/impl/import_linter.py +++ b/src/usethis/_tool/impl/import_linter.py @@ -15,8 +15,8 @@ from usethis._integrations.file.ini.io_ import INIFileManager from usethis._integrations.file.pyproject_toml.io_ import PyprojectTOMLManager from usethis._integrations.file.setup_cfg.io_ import SetupCFGManager +from usethis._integrations.pre_commit import schema as pre_commit_schema from usethis._integrations.pre_commit.language import get_system_language -from usethis._integrations.pre_commit.schema import HookDefinition, LocalRepo from usethis._integrations.project.errors import ImportGraphBuildFailedError from usethis._integrations.project.imports import ( LayeredArchitecture, @@ -335,10 +335,10 @@ def get_pre_commit_config(self) -> PreCommitConfig: if backend is BackendEnum.uv: return PreCommitConfig.from_single_repo( - LocalRepo( + pre_commit_schema.LocalRepo( repo="local", hooks=[ - HookDefinition( + pre_commit_schema.HookDefinition( id="import-linter", name="import-linter", pass_filenames=False, @@ -354,10 +354,10 @@ def get_pre_commit_config(self) -> PreCommitConfig: ) elif backend is BackendEnum.none: return PreCommitConfig.from_single_repo( - LocalRepo( + pre_commit_schema.LocalRepo( repo="local", hooks=[ - HookDefinition( + pre_commit_schema.HookDefinition( id="import-linter", name="import-linter", pass_filenames=False, diff --git a/src/usethis/_tool/impl/pre_commit.py b/src/usethis/_tool/impl/pre_commit.py index df48b2f4..c24ff67d 100644 --- a/src/usethis/_tool/impl/pre_commit.py +++ b/src/usethis/_tool/impl/pre_commit.py @@ -8,12 +8,11 @@ from usethis._console import how_print from usethis._integrations.backend.dispatch import get_backend from usethis._integrations.backend.uv.used import is_uv_used +from usethis._integrations.ci.bitbucket import schema as bitbucket_schema from usethis._integrations.ci.bitbucket.anchor import ( ScriptItemAnchor as BitbucketScriptItemAnchor, ) -from usethis._integrations.ci.bitbucket.schema import Script as BitbucketScript -from usethis._integrations.ci.bitbucket.schema import Step as BitbucketStep -from usethis._integrations.pre_commit.schema import HookDefinition, UriRepo +from usethis._integrations.pre_commit import schema as pre_commit_schema from usethis._tool.base import Tool from usethis._tool.pre_commit import PreCommitConfig from usethis._types.backend import BackendEnum @@ -34,10 +33,10 @@ def get_pre_commit_config(self) -> PreCommitConfig: if backend is BackendEnum.uv: return PreCommitConfig.from_single_repo( - UriRepo( + pre_commit_schema.UriRepo( repo="https://github.com/tsvikas/sync-with-uv", rev=_SYNC_WITH_UV_VERSION, - hooks=[HookDefinition(id="sync-with-uv")], + hooks=[pre_commit_schema.HookDefinition(id="sync-with-uv")], ), requires_venv=False, inform_how_to_use_on_migrate=False, @@ -69,15 +68,17 @@ def get_dev_deps(self, *, unconditional: bool = False) -> list[Dependency]: def get_managed_files(self) -> list[Path]: return [Path(".pre-commit-config.yaml")] - def get_bitbucket_steps(self, *, matrix_python: bool = True) -> list[BitbucketStep]: + def get_bitbucket_steps( + self, *, matrix_python: bool = True + ) -> list[bitbucket_schema.Step]: backend = get_backend() if backend is BackendEnum.uv: return [ - BitbucketStep( + bitbucket_schema.Step( name=f"Run {self.name}", caches=["uv", "pre-commit"], - script=BitbucketScript( + script=bitbucket_schema.Script( [ BitbucketScriptItemAnchor(name="install-uv"), "uv run pre-commit run --all-files", @@ -87,10 +88,10 @@ def get_bitbucket_steps(self, *, matrix_python: bool = True) -> list[BitbucketSt ] elif backend is BackendEnum.none: return [ - BitbucketStep( + bitbucket_schema.Step( name=f"Run {self.name}", caches=["pre-commit"], - script=BitbucketScript( + script=bitbucket_schema.Script( [ BitbucketScriptItemAnchor(name="ensure-venv"), "pre-commit run --all-files", diff --git a/src/usethis/_tool/impl/pyproject_fmt.py b/src/usethis/_tool/impl/pyproject_fmt.py index cfa27cf1..5396066b 100644 --- a/src/usethis/_tool/impl/pyproject_fmt.py +++ b/src/usethis/_tool/impl/pyproject_fmt.py @@ -8,7 +8,7 @@ from usethis._integrations.backend.dispatch import get_backend from usethis._integrations.backend.uv.used import is_uv_used from usethis._integrations.file.pyproject_toml.io_ import PyprojectTOMLManager -from usethis._integrations.pre_commit.schema import HookDefinition, UriRepo +from usethis._integrations.pre_commit import schema as pre_commit_schema from usethis._tool.base import Tool from usethis._tool.config import ConfigEntry, ConfigItem, ConfigSpec from usethis._tool.pre_commit import PreCommitConfig @@ -85,10 +85,10 @@ def get_config_spec(self) -> ConfigSpec: def get_pre_commit_config(self) -> PreCommitConfig: return PreCommitConfig.from_single_repo( - UriRepo( + pre_commit_schema.UriRepo( repo="https://github.com/tox-dev/pyproject-fmt", rev=_PYPROJECT_FMT_VERSION, - hooks=[HookDefinition(id="pyproject-fmt")], + hooks=[pre_commit_schema.HookDefinition(id="pyproject-fmt")], ), requires_venv=False, ) diff --git a/src/usethis/_tool/impl/pytest.py b/src/usethis/_tool/impl/pytest.py index f8a1ea8c..803e1719 100644 --- a/src/usethis/_tool/impl/pytest.py +++ b/src/usethis/_tool/impl/pytest.py @@ -11,12 +11,10 @@ from usethis._console import how_print, info_print, instruct_print from usethis._integrations.backend.dispatch import get_backend from usethis._integrations.backend.uv.used import is_uv_used +from usethis._integrations.ci.bitbucket import schema as bitbucket_schema from usethis._integrations.ci.bitbucket.anchor import ( ScriptItemAnchor as BitbucketScriptItemAnchor, ) -from usethis._integrations.ci.bitbucket.schema import Image, ImageName -from usethis._integrations.ci.bitbucket.schema import Script as BitbucketScript -from usethis._integrations.ci.bitbucket.schema import Step as BitbucketStep from usethis._integrations.ci.bitbucket.steps import get_steps_in_default from usethis._integrations.ci.bitbucket.used import is_bitbucket_used from usethis._integrations.environ.python import get_supported_minor_python_versions @@ -223,7 +221,9 @@ def get_active_config_file_managers(self) -> set[KeyValueFileManager]: raise NotImplementedError(msg) return {preferred_file_manager} - def get_bitbucket_steps(self, *, matrix_python: bool = True) -> list[BitbucketStep]: + def get_bitbucket_steps( + self, *, matrix_python: bool = True + ) -> list[bitbucket_schema.Step]: if matrix_python: versions = get_supported_minor_python_versions() else: @@ -234,10 +234,10 @@ def get_bitbucket_steps(self, *, matrix_python: bool = True) -> list[BitbucketSt steps = [] for version in versions: if backend is BackendEnum.uv: - step = BitbucketStep( + step = bitbucket_schema.Step( name=f"Test on {version.to_short_string()}", caches=["uv"], - script=BitbucketScript( + script=bitbucket_schema.Script( [ BitbucketScriptItemAnchor(name="install-uv"), f"uv run --python {version.to_short_string()} pytest -x --junitxml=test-reports/report.xml", @@ -245,10 +245,14 @@ def get_bitbucket_steps(self, *, matrix_python: bool = True) -> list[BitbucketSt ), ) elif backend is BackendEnum.none: - step = BitbucketStep( + step = bitbucket_schema.Step( name=f"Test on {version.to_short_string()}", - image=Image(ImageName(f"python:{version.to_short_string()}")), - script=BitbucketScript( + image=bitbucket_schema.Image( + bitbucket_schema.ImageName( + f"python:{version.to_short_string()}" + ) + ), + script=bitbucket_schema.Script( [ BitbucketScriptItemAnchor(name="ensure-venv"), _PYTEST_PIP_CMD, diff --git a/src/usethis/_tool/impl/requirements_txt.py b/src/usethis/_tool/impl/requirements_txt.py index 6a012586..261f52dd 100644 --- a/src/usethis/_tool/impl/requirements_txt.py +++ b/src/usethis/_tool/impl/requirements_txt.py @@ -8,8 +8,8 @@ from usethis._config import usethis_config from usethis._console import how_print from usethis._integrations.backend.dispatch import get_backend +from usethis._integrations.pre_commit import schema as pre_commit_schema from usethis._integrations.pre_commit.language import get_system_language -from usethis._integrations.pre_commit.schema import HookDefinition, LocalRepo from usethis._tool.base import Tool from usethis._tool.pre_commit import PreCommitConfig from usethis._types.backend import BackendEnum @@ -65,10 +65,10 @@ def get_pre_commit_config(self) -> PreCommitConfig: if backend is BackendEnum.uv: return PreCommitConfig.from_single_repo( - LocalRepo( + pre_commit_schema.LocalRepo( repo="local", hooks=[ - HookDefinition( + pre_commit_schema.HookDefinition( id="uv-export", name="uv-export", files="^uv\\.lock$", diff --git a/src/usethis/_tool/impl/ruff.py b/src/usethis/_tool/impl/ruff.py index 82902688..8e99c950 100644 --- a/src/usethis/_tool/impl/ruff.py +++ b/src/usethis/_tool/impl/ruff.py @@ -10,16 +10,12 @@ from usethis._console import how_print, tick_print from usethis._integrations.backend.dispatch import get_backend from usethis._integrations.backend.uv.used import is_uv_used +from usethis._integrations.ci.bitbucket import schema as bitbucket_schema from usethis._integrations.ci.bitbucket.anchor import ( ScriptItemAnchor as BitbucketScriptItemAnchor, ) -from usethis._integrations.ci.bitbucket.schema import Script as BitbucketScript -from usethis._integrations.ci.bitbucket.schema import Step as BitbucketStep from usethis._integrations.file.pyproject_toml.io_ import PyprojectTOMLManager -from usethis._integrations.pre_commit.schema import ( - HookDefinition, - UriRepo, -) +from usethis._integrations.pre_commit import schema as pre_commit_schema from usethis._tool.base import Tool from usethis._tool.config import ( ConfigEntry, @@ -246,10 +242,10 @@ def get_pre_commit_config(self) -> PreCommitConfig: if self.is_linter_used(): repo_configs.append( PreCommitRepoConfig( - repo=UriRepo( + repo=pre_commit_schema.UriRepo( repo="https://github.com/astral-sh/ruff-pre-commit", rev=_RUFF_VERSION, - hooks=[HookDefinition(id="ruff-check")], + hooks=[pre_commit_schema.HookDefinition(id="ruff-check")], ), requires_venv=False, ), @@ -257,10 +253,10 @@ def get_pre_commit_config(self) -> PreCommitConfig: if self.is_formatter_used(): repo_configs.append( PreCommitRepoConfig( - repo=UriRepo( + repo=pre_commit_schema.UriRepo( repo="https://github.com/astral-sh/ruff-pre-commit", rev=_RUFF_VERSION, - hooks=[HookDefinition(id="ruff-format")], + hooks=[pre_commit_schema.HookDefinition(id="ruff-format")], ), requires_venv=False, ), @@ -270,17 +266,19 @@ def get_pre_commit_config(self) -> PreCommitConfig: inform_how_to_use_on_migrate=True, # The pre-commit commands are not simpler than the venv-based commands ) - def get_bitbucket_steps(self, *, matrix_python: bool = True) -> list[BitbucketStep]: + def get_bitbucket_steps( + self, *, matrix_python: bool = True + ) -> list[bitbucket_schema.Step]: backend = get_backend() steps = [] if self.is_linter_used(): if backend is BackendEnum.uv: steps.append( - BitbucketStep( + bitbucket_schema.Step( name=f"Run {self.name}", caches=["uv"], - script=BitbucketScript( + script=bitbucket_schema.Script( [ BitbucketScriptItemAnchor(name="install-uv"), "uv run ruff check --fix", @@ -290,9 +288,9 @@ def get_bitbucket_steps(self, *, matrix_python: bool = True) -> list[BitbucketSt ) elif backend is BackendEnum.none: steps.append( - BitbucketStep( + bitbucket_schema.Step( name=f"Run {self.name}", - script=BitbucketScript( + script=bitbucket_schema.Script( [ BitbucketScriptItemAnchor(name="ensure-venv"), "ruff check --fix", @@ -306,10 +304,10 @@ def get_bitbucket_steps(self, *, matrix_python: bool = True) -> list[BitbucketSt if self.is_formatter_used(): if backend is BackendEnum.uv: steps.append( - BitbucketStep( + bitbucket_schema.Step( name=f"Run {self.name} Formatter", caches=["uv"], - script=BitbucketScript( + script=bitbucket_schema.Script( [ BitbucketScriptItemAnchor(name="install-uv"), "uv run ruff format", @@ -319,9 +317,9 @@ def get_bitbucket_steps(self, *, matrix_python: bool = True) -> list[BitbucketSt ) elif backend is BackendEnum.none: steps.append( - BitbucketStep( + bitbucket_schema.Step( name=f"Run {self.name} Formatter", - script=BitbucketScript( + script=bitbucket_schema.Script( [ BitbucketScriptItemAnchor(name="ensure-venv"), "ruff format", diff --git a/src/usethis/_tool/pre_commit.py b/src/usethis/_tool/pre_commit.py index 680fe5c1..0e79b37d 100644 --- a/src/usethis/_tool/pre_commit.py +++ b/src/usethis/_tool/pre_commit.py @@ -4,7 +4,7 @@ from pydantic import BaseModel -from usethis._integrations.pre_commit.schema import LocalRepo, UriRepo +from usethis._integrations.pre_commit import schema if TYPE_CHECKING: from typing_extensions import Self @@ -18,7 +18,7 @@ class PreCommitRepoConfig(BaseModel): requires_venv: Whether the repository requires a virtual environment to run. """ - repo: LocalRepo | UriRepo + repo: schema.LocalRepo | schema.UriRepo requires_venv: bool @@ -43,7 +43,7 @@ class PreCommitConfig(BaseModel): @classmethod def from_single_repo( cls, - repo: LocalRepo | UriRepo, + repo: schema.LocalRepo | schema.UriRepo, *, requires_venv: bool, inform_how_to_use_on_migrate: bool = True, diff --git a/tests/usethis/_integrations/ci/bitbucket/test_bitbucket_config.py b/tests/usethis/_integrations/ci/bitbucket/test_bitbucket_config.py index e35f6fc8..e58d467f 100644 --- a/tests/usethis/_integrations/ci/bitbucket/test_bitbucket_config.py +++ b/tests/usethis/_integrations/ci/bitbucket/test_bitbucket_config.py @@ -1,14 +1,13 @@ from pathlib import Path from usethis._config_file import files_manager +from usethis._integrations.ci.bitbucket import schema from usethis._integrations.ci.bitbucket.anchor import ScriptItemAnchor from usethis._integrations.ci.bitbucket.config import ( add_bitbucket_pipelines_config, remove_bitbucket_pipelines_config, ) -from usethis._integrations.ci.bitbucket.schema import Model, Script from usethis._integrations.ci.bitbucket.steps import ( - Step, add_bitbucket_step_in_default, ) from usethis._integrations.ci.bitbucket.yaml import BitbucketPipelinesYAMLManager @@ -71,9 +70,9 @@ def test_satisfies_schema(self, uv_init_dir: Path): ): add_bitbucket_pipelines_config() add_bitbucket_step_in_default( - Step( + schema.Step( name="Example step", - script=Script( + script=schema.Script( [ScriptItemAnchor(name="install-uv"), "echo 'Hello, world!'"] ), ), @@ -81,7 +80,7 @@ def test_satisfies_schema(self, uv_init_dir: Path): # Assert with edit_yaml(uv_init_dir / "bitbucket-pipelines.yml") as yaml_document: - assert Model.model_validate(yaml_document.content) + assert schema.Model.model_validate(yaml_document.content) class TestRemoveBitbucketPipelineConfig: diff --git a/tests/usethis/_integrations/ci/bitbucket/test_bitbucket_schema.py b/tests/usethis/_integrations/ci/bitbucket/test_bitbucket_schema.py index 50893987..c4ab8135 100644 --- a/tests/usethis/_integrations/ci/bitbucket/test_bitbucket_schema.py +++ b/tests/usethis/_integrations/ci/bitbucket/test_bitbucket_schema.py @@ -5,7 +5,7 @@ import requests from requests.exceptions import RequestException -from usethis._integrations.ci.bitbucket.schema import Script, Step, Step2, StepBase +from usethis._integrations.ci.bitbucket import schema from usethis._integrations.file.pyproject_toml.io_ import PyprojectTOMLManager from usethis._integrations.file.pyproject_toml.requires_python import ( get_requires_python, @@ -15,11 +15,13 @@ class TestStep2: def test_shared_parent(self): - assert isinstance(Step2(script=Script(["hi"])), StepBase) - assert isinstance(Step(script=Script(["hi"])), StepBase) + assert isinstance(schema.Step2(script=schema.Script(["hi"])), schema.StepBase) + assert isinstance(schema.Step(script=schema.Script(["hi"])), schema.StepBase) def test_field_subset(self): - assert set(Step2.model_fields.keys()) == set(Step.model_fields.keys()) + assert set(schema.Step2.model_fields.keys()) == set( + schema.Step.model_fields.keys() + ) class TestSchemaJSON: diff --git a/tests/usethis/_integrations/ci/bitbucket/test_cache.py b/tests/usethis/_integrations/ci/bitbucket/test_cache.py index d2f280a3..744d5808 100644 --- a/tests/usethis/_integrations/ci/bitbucket/test_cache.py +++ b/tests/usethis/_integrations/ci/bitbucket/test_cache.py @@ -3,20 +3,20 @@ import pytest from usethis._config_file import files_manager +from usethis._integrations.ci.bitbucket import schema from usethis._integrations.ci.bitbucket.cache import ( add_caches, get_cache_by_name, remove_cache, ) from usethis._integrations.ci.bitbucket.config import add_bitbucket_pipelines_config -from usethis._integrations.ci.bitbucket.schema import Cache, CachePath from usethis._test import change_cwd class TestAddCaches: def test_in_caches(self, uv_init_dir: Path, capfd: pytest.CaptureFixture[str]): # Arrange - cache_by_name = {"example": Cache(CachePath("~/.cache/example"))} + cache_by_name = {"example": schema.Cache(schema.CachePath("~/.cache/example"))} with change_cwd(uv_init_dir), files_manager(): add_bitbucket_pipelines_config() @@ -26,7 +26,9 @@ def test_in_caches(self, uv_init_dir: Path, capfd: pytest.CaptureFixture[str]): add_caches(cache_by_name) # Assert - default_cache_by_name = {"uv": Cache(CachePath("~/.cache/uv"))} + default_cache_by_name = { + "uv": schema.Cache(schema.CachePath("~/.cache/uv")) + } assert get_cache_by_name() == cache_by_name | default_cache_by_name out, err = capfd.readouterr() assert not err @@ -37,7 +39,9 @@ def test_in_caches(self, uv_init_dir: Path, capfd: pytest.CaptureFixture[str]): def test_already_exists(self, uv_init_dir: Path): # Arrange cache_by_name = { - "uv": Cache(CachePath("~/.cache/uv")) # uv cache is in the default config + "uv": schema.Cache( + schema.CachePath("~/.cache/uv") + ) # uv cache is in the default config } # Act @@ -51,7 +55,7 @@ def test_already_exists(self, uv_init_dir: Path): def test_definitions_order(self, tmp_path: Path): """Test that the newly-created definitions section is placed after the image.""" # Arrange - cache_by_name = {"example": Cache(CachePath("~/.cache/example"))} + cache_by_name = {"example": schema.Cache(schema.CachePath("~/.cache/example"))} (tmp_path / "bitbucket-pipelines.yml").write_text( """\ @@ -126,7 +130,7 @@ def test_roundtrip(self, uv_init_dir: Path): with change_cwd(uv_init_dir), files_manager(): # Arrange add_bitbucket_pipelines_config() - add_caches({"mycache": Cache(CachePath("~/.cache/mytool"))}) + add_caches({"mycache": schema.Cache(schema.CachePath("~/.cache/mytool"))}) # Act remove_cache("mycache") diff --git a/tests/usethis/_integrations/ci/bitbucket/test_pipeweld.py b/tests/usethis/_integrations/ci/bitbucket/test_pipeweld.py index 3f2f9def..c20bbd67 100644 --- a/tests/usethis/_integrations/ci/bitbucket/test_pipeweld.py +++ b/tests/usethis/_integrations/ci/bitbucket/test_pipeweld.py @@ -4,32 +4,13 @@ import pytest from usethis._config_file import files_manager +from usethis._integrations.ci.bitbucket import schema from usethis._integrations.ci.bitbucket.errors import UnexpectedImportPipelineError from usethis._integrations.ci.bitbucket.pipeweld import ( apply_pipeweld_instruction, get_pipeweld_pipeline_from_default, get_pipeweld_step, ) -from usethis._integrations.ci.bitbucket.schema import ( - Image, - ImageName, - ImportPipeline, - Items, - Parallel, - ParallelExpanded, - ParallelItem, - ParallelSteps, - Pipeline, - Pipelines, - PipelinesConfiguration, - Script, - Stage, - StageItem, - Step, - Step1, - Step2, - StepItem, -) from usethis._pipeweld.containers import DepGroup, depgroup, parallel, series from usethis._pipeweld.func import _get_instructions_for_insertion from usethis._pipeweld.ops import InsertParallel, InsertSuccessor @@ -42,7 +23,9 @@ def test_add_to_brand_new_pipeline(self, tmp_path: Path): with change_cwd(tmp_path), files_manager(): apply_pipeweld_instruction( InsertSuccessor(step="foo", after=None), - step_to_insert=Step(name="foo", script=Script(["echo foo"])), + step_to_insert=schema.Step( + name="foo", script=schema.Script(["echo foo"]) + ), ) # Assert @@ -79,7 +62,9 @@ def test_import_pipeline_fails(self, tmp_path: Path): ): apply_pipeweld_instruction( InsertSuccessor(step="foo", after=None), - step_to_insert=Step(name="foo", script=Script(["echo foo"])), + step_to_insert=schema.Step( + name="foo", script=schema.Script(["echo foo"]) + ), ) def test_existing_pipeline(self, tmp_path: Path): @@ -100,7 +85,9 @@ def test_existing_pipeline(self, tmp_path: Path): with change_cwd(tmp_path), files_manager(): apply_pipeweld_instruction( InsertSuccessor(step="foo", after=None), - step_to_insert=Step(name="foo", script=Script(["echo foo"])), + step_to_insert=schema.Step( + name="foo", script=schema.Script(["echo foo"]) + ), ) # Assert @@ -141,7 +128,9 @@ def test_step_item(self, tmp_path: Path): with change_cwd(tmp_path), files_manager(): apply_pipeweld_instruction( InsertSuccessor(step="foo", after="bar"), - step_to_insert=Step(name="foo", script=Script(["echo foo"])), + step_to_insert=schema.Step( + name="foo", script=schema.Script(["echo foo"]) + ), ) # Assert @@ -186,7 +175,9 @@ def test_parallel_item(self, tmp_path: Path): with change_cwd(tmp_path), files_manager(): apply_pipeweld_instruction( InsertSuccessor(step="foo", after="qux"), - step_to_insert=Step(name="foo", script=Script(["echo foo"])), + step_to_insert=schema.Step( + name="foo", script=schema.Script(["echo foo"]) + ), ) # Assert @@ -237,7 +228,9 @@ def test_parallel_expanded(self, tmp_path: Path): with change_cwd(tmp_path), files_manager(): apply_pipeweld_instruction( InsertSuccessor(step="foo", after="qux"), - step_to_insert=Step(name="foo", script=Script(["echo foo"])), + step_to_insert=schema.Step( + name="foo", script=schema.Script(["echo foo"]) + ), ) # Assert @@ -285,7 +278,9 @@ def test_stage_item(self, tmp_path: Path): with change_cwd(tmp_path), files_manager(): apply_pipeweld_instruction( InsertSuccessor(step="foo", after="baz"), - step_to_insert=Step(name="foo", script=Script(["echo foo"])), + step_to_insert=schema.Step( + name="foo", script=schema.Script(["echo foo"]) + ), ) # Assert @@ -328,7 +323,9 @@ def test_simple_step(self, tmp_path: Path): with change_cwd(tmp_path), files_manager(): apply_pipeweld_instruction( InsertParallel(step="foo", after="bar"), - step_to_insert=Step(name="foo", script=Script(["echo foo"])), + step_to_insert=schema.Step( + name="foo", script=schema.Script(["echo foo"]) + ), ) # Assert: Should create a parallel block with both steps @@ -374,7 +371,9 @@ def test_add_to_existing_parallel(self, tmp_path: Path): with change_cwd(tmp_path), files_manager(): apply_pipeweld_instruction( InsertParallel(step="foo", after="bar"), - step_to_insert=Step(name="foo", script=Script(["echo foo"])), + step_to_insert=schema.Step( + name="foo", script=schema.Script(["echo foo"]) + ), ) # Assert: Should add to the existing parallel block @@ -413,7 +412,9 @@ def test_parallel_after_none(self, tmp_path: Path): with change_cwd(tmp_path), files_manager(): apply_pipeweld_instruction( InsertParallel(step="foo", after=None), - step_to_insert=Step(name="foo", script=Script(["echo foo"])), + step_to_insert=schema.Step( + name="foo", script=schema.Script(["echo foo"]) + ), ) # Assert: Should just add the step (parallel with no other steps is just a step) @@ -455,7 +456,9 @@ def test_add_to_existing_parallel_expanded_format(self, tmp_path: Path): with change_cwd(tmp_path), files_manager(): apply_pipeweld_instruction( InsertParallel(step="foo", after="bar"), - step_to_insert=Step(name="foo", script=Script(["echo foo"])), + step_to_insert=schema.Step( + name="foo", script=schema.Script(["echo foo"]) + ), ) # Assert: Should add to the existing parallel block @@ -515,19 +518,19 @@ def test_full_parallel_breakup_sequence(self, tmp_path: Path): # Step 1: Move A to beginning apply_pipeweld_instruction( InsertSuccessor(step="A", after=None), - step_to_insert=Step(name="C", script=Script(["echo C"])), + step_to_insert=schema.Step(name="C", script=schema.Script(["echo C"])), ) # Step 2: Move B after A apply_pipeweld_instruction( InsertSuccessor(step="B", after="A"), - step_to_insert=Step(name="C", script=Script(["echo C"])), + step_to_insert=schema.Step(name="C", script=schema.Script(["echo C"])), ) # Step 3: Insert C after A (C will go between A and B) apply_pipeweld_instruction( InsertSuccessor(step="C", after="A"), - step_to_insert=Step(name="C", script=Script(["echo C"])), + step_to_insert=schema.Step(name="C", script=schema.Script(["echo C"])), ) # Assert: Should result in A, then C, then B in series @@ -576,7 +579,7 @@ def test_extract_last_step_from_parallel(self, tmp_path: Path): with change_cwd(tmp_path), files_manager(): apply_pipeweld_instruction( InsertSuccessor(step="A", after=None), - step_to_insert=Step(name="C", script=Script(["echo C"])), + step_to_insert=schema.Step(name="C", script=schema.Script(["echo C"])), ) # Assert: Parallel block should be removed entirely, leaving A and B @@ -747,8 +750,8 @@ def test_basic(self): class TestGetPipeweldPipelineFromDefault: def test_image_only(self): # Arrange - model = PipelinesConfiguration( - image=Image(ImageName("atlassian/default-image:3")) + model = schema.PipelinesConfiguration( + image=schema.Image(schema.ImageName("atlassian/default-image:3")) ) # Act @@ -759,10 +762,10 @@ def test_image_only(self): def test_import_pipeline_raises(self): # Arrange - model = PipelinesConfiguration( - pipelines=Pipelines( - default=Pipeline( - ImportPipeline( + model = schema.PipelinesConfiguration( + pipelines=schema.Pipelines( + default=schema.Pipeline( + schema.ImportPipeline( # import is a keyword so we need to use a dict **{"import": "shared-pipeline:master:share-pipeline-1"} ) @@ -776,15 +779,15 @@ def test_import_pipeline_raises(self): def test_series(self): # Arrange - model = PipelinesConfiguration( - pipelines=Pipelines( - default=Pipeline( - Items( + model = schema.PipelinesConfiguration( + pipelines=schema.Pipelines( + default=schema.Pipeline( + schema.Items( [ - StepItem( - step=Step( + schema.StepItem( + step=schema.Step( name="foo", - script=Script(["echo foo"]), + script=schema.Script(["echo foo"]), ) ) ] @@ -801,25 +804,25 @@ def test_series(self): def test_parallel(self): # Arrange - model = PipelinesConfiguration( - pipelines=Pipelines( - default=Pipeline( - Items( + model = schema.PipelinesConfiguration( + pipelines=schema.Pipelines( + default=schema.Pipeline( + schema.Items( [ - ParallelItem( - parallel=Parallel( - ParallelSteps( + schema.ParallelItem( + parallel=schema.Parallel( + schema.ParallelSteps( [ - StepItem( - step=Step( + schema.StepItem( + step=schema.Step( name="foo", - script=Script(["echo foo"]), + script=schema.Script(["echo foo"]), ) ), - StepItem( - step=Step( + schema.StepItem( + step=schema.Step( name="bar", - script=Script(["echo bar"]), + script=schema.Script(["echo bar"]), ) ), ] @@ -842,26 +845,30 @@ def test_parallel(self): def test_parallel_expanded(self): # Arrange - model = PipelinesConfiguration( - pipelines=Pipelines( - default=Pipeline( - Items( + model = schema.PipelinesConfiguration( + pipelines=schema.Pipelines( + default=schema.Pipeline( + schema.Items( [ - ParallelItem( - parallel=Parallel( - ParallelExpanded( - steps=ParallelSteps( + schema.ParallelItem( + parallel=schema.Parallel( + schema.ParallelExpanded( + steps=schema.ParallelSteps( [ - StepItem( - step=Step( + schema.StepItem( + step=schema.Step( name="foo", - script=Script(["echo foo"]), + script=schema.Script( + ["echo foo"] + ), ) ), - StepItem( - step=Step( + schema.StepItem( + step=schema.Step( name="bar", - script=Script(["echo bar"]), + script=schema.Script( + ["echo bar"] + ), ) ), ] @@ -885,19 +892,19 @@ def test_parallel_expanded(self): def test_named_stage_item(self): # Arrange - model = PipelinesConfiguration( - pipelines=Pipelines( - default=Pipeline( - Items( + model = schema.PipelinesConfiguration( + pipelines=schema.Pipelines( + default=schema.Pipeline( + schema.Items( [ - StageItem( - stage=Stage( + schema.StageItem( + stage=schema.Stage( name="mystage", steps=[ - Step1( - step=Step2( + schema.Step1( + step=schema.Step2( name="foo", - script=Script(["echo foo"]), + script=schema.Script(["echo foo"]), ) ) ], @@ -922,18 +929,18 @@ def test_named_stage_item(self): def test_unnamed_stage_item(self): # Arrange - model = PipelinesConfiguration( - pipelines=Pipelines( - default=Pipeline( - Items( + model = schema.PipelinesConfiguration( + pipelines=schema.Pipelines( + default=schema.Pipeline( + schema.Items( [ - StageItem( - stage=Stage( + schema.StageItem( + stage=schema.Stage( steps=[ - Step1( - step=Step2( + schema.Step1( + step=schema.Step2( name="foo", - script=Script(["echo foo"]), + script=schema.Script(["echo foo"]), ) ) ], @@ -965,9 +972,9 @@ def test_unnamed_stage_item(self): class TestGetPipeweldStep: def test_no_name(self): # Arrange - step = Step( + step = schema.Step( name=None, - script=Script(["echo foo"]), + script=schema.Script(["echo foo"]), ) # Act @@ -978,9 +985,9 @@ def test_no_name(self): def test_with_name(self): # Arrange - step = Step( + step = schema.Step( name="foo", - script=Script(["echo foo"]), + script=schema.Script(["echo foo"]), ) # Act diff --git a/tests/usethis/_integrations/ci/bitbucket/test_steps.py b/tests/usethis/_integrations/ci/bitbucket/test_steps.py index 7ede0506..44baf186 100644 --- a/tests/usethis/_integrations/ci/bitbucket/test_steps.py +++ b/tests/usethis/_integrations/ci/bitbucket/test_steps.py @@ -4,25 +4,13 @@ from usethis._config import usethis_config from usethis._config_file import files_manager +from usethis._integrations.ci.bitbucket import schema from usethis._integrations.ci.bitbucket.anchor import ScriptItemAnchor from usethis._integrations.ci.bitbucket.init import ( ensure_bitbucket_pipelines_config_exists, ) -from usethis._integrations.ci.bitbucket.schema import ( - Parallel, - ParallelExpanded, - ParallelItem, - ParallelSteps, - Script, - Stage, - StageItem, - Step1, - Step2, - StepItem, -) from usethis._integrations.ci.bitbucket.steps import ( _CACHE_LOOKUP, - Step, UnexpectedImportPipelineError, _add_step_caches_via_model, add_bitbucket_step_in_default, @@ -54,9 +42,9 @@ def test_contents(self, uv_init_dir: Path): # Act with change_cwd(uv_init_dir), files_manager(): add_bitbucket_step_in_default( - Step( + schema.Step( name="Greeting", - script=Script(["echo 'Why, hello!'"]), + script=schema.Script(["echo 'Why, hello!'"]), ), ) @@ -92,9 +80,9 @@ def test_pipeline_doesnt_exist(self, uv_init_dir: Path): # Act with change_cwd(uv_init_dir), files_manager(): add_bitbucket_step_in_default( - Step( + schema.Step( name="Greeting", - script=Script(["echo 'Hello, world!'"]), + script=schema.Script(["echo 'Hello, world!'"]), ) ) @@ -126,10 +114,10 @@ def test_with_caches(self, uv_init_dir: Path): # Act with change_cwd(uv_init_dir), files_manager(): add_bitbucket_step_in_default( - Step( + schema.Step( name="Greeting", caches=["uv"], - script=Script(["echo 'Hello, world!'"]), + script=schema.Script(["echo 'Hello, world!'"]), ) ) @@ -154,9 +142,9 @@ def test_with_caches(self, uv_init_dir: Path): ) def test_add_same_step_twice(self, uv_init_dir: Path): # Arrange - step = Step( + step = schema.Step( name="Greeting", - script=Script( + script=schema.Script( [ ScriptItemAnchor(name="install-uv"), "echo 'Hello, world!'", @@ -180,18 +168,18 @@ def test_add_different_steps_sharing_same_script_step_anchor( self, uv_init_dir: Path ): # Assert - step = Step( + step = schema.Step( name="Greeting", - script=Script( + script=schema.Script( [ ScriptItemAnchor(name="install-uv"), "echo 'Hello, world!'", ] ), ) - other_step = Step( + other_step = schema.Step( name="Farewell", - script=Script( + script=schema.Script( [ ScriptItemAnchor(name="install-uv"), "echo 'Goodbye!'", @@ -216,16 +204,16 @@ def test_order(self, uv_init_dir: Path, capfd: pytest.CaptureFixture[str]): with change_cwd(uv_init_dir), files_manager(): # This step should be listed second add_bitbucket_step_in_default( - Step( + schema.Step( name="Test on 3.12", - script=Script(["echo 'Running #2'"]), + script=schema.Script(["echo 'Running #2'"]), ), ) # This one should come first add_bitbucket_step_in_default( - Step( + schema.Step( name="Run pre-commit", - script=Script(["echo 'Running #1'"]), + script=schema.Script(["echo 'Running #1'"]), ), ) @@ -265,9 +253,9 @@ def test_placeholder_removed( # Act add_bitbucket_step_in_default( - Step( + schema.Step( name="Greeting", - script=Script(["echo 'Hello, world!'"]), + script=schema.Script(["echo 'Hello, world!'"]), ) ) @@ -328,9 +316,9 @@ def test_add_script_item_to_existing_file( # Act with change_cwd(uv_init_dir), files_manager(): add_bitbucket_step_in_default( - Step( + schema.Step( name="Farewell", - script=Script( + script=schema.Script( [ ScriptItemAnchor(name="install-uv"), "echo 'Goodbye!'", @@ -396,9 +384,9 @@ def test_script_items_canonical_order_install_uv_first(self, uv_init_dir: Path): # Act - add a step that uses install-uv with change_cwd(uv_init_dir), files_manager(): add_bitbucket_step_in_default( - Step( + schema.Step( name="Install uv", - script=Script( + script=schema.Script( [ ScriptItemAnchor(name="install-uv"), "echo 'uv installed!'", @@ -469,9 +457,9 @@ def test_script_items_canonical_order_ensure_venv_after_install_uv( # Act - add a step that uses ensure-venv with change_cwd(uv_init_dir), files_manager(): add_bitbucket_step_in_default( - Step( + schema.Step( name="Setup venv", - script=Script( + script=schema.Script( [ ScriptItemAnchor(name="ensure-venv"), "echo 'Environment ready!'", @@ -527,9 +515,9 @@ def test_script_items_canonical_order_multiple_items_reverse_order( with change_cwd(uv_init_dir), files_manager(): # Add ensure-venv first (should end up second) add_bitbucket_step_in_default( - Step( + schema.Step( name="Setup venv", - script=Script( + script=schema.Script( [ ScriptItemAnchor(name="ensure-venv"), "echo 'Environment ready!'", @@ -539,9 +527,9 @@ def test_script_items_canonical_order_multiple_items_reverse_order( ) # Add install-uv second (should end up first) add_bitbucket_step_in_default( - Step( + schema.Step( name="Install uv", - script=Script( + script=schema.Script( [ ScriptItemAnchor(name="install-uv"), "echo 'uv installed!'", @@ -609,9 +597,9 @@ def test_script_items_canonical_order_with_existing_non_canonical_items( # Act - add a step that uses install-uv with change_cwd(uv_init_dir), files_manager(): add_bitbucket_step_in_default( - Step( + schema.Step( name="Install uv", - script=Script( + script=schema.Script( [ ScriptItemAnchor(name="install-uv"), "echo 'uv installed!'", @@ -677,9 +665,9 @@ def test_remove_remove_one_step(self, tmp_path: Path): # Act with change_cwd(tmp_path), files_manager(): remove_bitbucket_step_from_default( - Step( + schema.Step( name="Greeting", - script=Script(["echo 'Hello, world!'"]), + script=schema.Script(["echo 'Hello, world!'"]), ) ) @@ -702,9 +690,9 @@ def test_no_file(self, tmp_path: Path): # Act with change_cwd(tmp_path), files_manager(): remove_bitbucket_step_from_default( - Step( + schema.Step( name="Greeting", - script=Script(["echo 'Hello, world!'"]), + script=schema.Script(["echo 'Hello, world!'"]), ) ) @@ -722,9 +710,9 @@ def test_no_default_pipeline(self, tmp_path: Path): # Act with change_cwd(tmp_path), files_manager(): remove_bitbucket_step_from_default( - Step( + schema.Step( name="Greeting", - script=Script(["echo 'Hello, world!'"]), + script=schema.Script(["echo 'Hello, world!'"]), ) ) @@ -741,9 +729,9 @@ def test_no_pipelines(self, tmp_path: Path): # Act with change_cwd(tmp_path), files_manager(): remove_bitbucket_step_from_default( - Step( + schema.Step( name="Greeting", - script=Script(["echo 'Hello, world!'"]), + script=schema.Script(["echo 'Hello, world!'"]), ) ) @@ -768,9 +756,9 @@ def test_import_pipeline_fails(self, tmp_path: Path): pytest.raises(UnexpectedImportPipelineError), ): remove_bitbucket_step_from_default( - Step( + schema.Step( name="Greeting", - script=Script(["echo 'Hello, world!'"]), + script=schema.Script(["echo 'Hello, world!'"]), ) ) @@ -796,9 +784,9 @@ def test_parallel_item(self, tmp_path: Path): # Act with change_cwd(tmp_path), files_manager(): remove_bitbucket_step_from_default( - Step( + schema.Step( name="Greeting", - script=Script(["echo 'Hello, world!'"]), + script=schema.Script(["echo 'Hello, world!'"]), ) ) @@ -839,9 +827,9 @@ def test_remove_single_parallel_step(self, tmp_path: Path): # Act with change_cwd(tmp_path), files_manager(): remove_bitbucket_step_from_default( - Step( + schema.Step( name="Greeting", - script=Script(["echo 'Hello, world!"]), + script=schema.Script(["echo 'Hello, world!"]), ) ) @@ -882,9 +870,9 @@ def test_remove_leaving_single_parallel_step(self, tmp_path: Path): # Act with change_cwd(tmp_path), files_manager(): remove_bitbucket_step_from_default( - Step( + schema.Step( name="Farewell", - script=Script(["echo 'Goodbye!'"]), + script=schema.Script(["echo 'Goodbye!'"]), ) ) @@ -921,9 +909,9 @@ def test_remove_step_leaving_placeholder(self, uv_init_dir: Path): # Act with change_cwd(uv_init_dir), files_manager(): remove_bitbucket_step_from_default( - Step( + schema.Step( name="Farewell", - script=Script(["echo 'Goodbye!'"]), + script=schema.Script(["echo 'Goodbye!'"]), ) ) @@ -978,9 +966,9 @@ def test_remove_expanded_parallel_step(self, tmp_path: Path): # Act with change_cwd(tmp_path), files_manager(): remove_bitbucket_step_from_default( - Step( + schema.Step( name="Greeting", - script=Script(["echo 'Hello, world!'"]), + script=schema.Script(["echo 'Hello, world!'"]), ) ) @@ -1023,9 +1011,9 @@ def test_remove_leaving_single_expanded_parallel_step(self, tmp_path: Path): # Act with change_cwd(tmp_path), files_manager(): remove_bitbucket_step_from_default( - Step( + schema.Step( name="Farewell", - script=Script(["echo 'Goodbye!'"]), + script=schema.Script(["echo 'Goodbye!'"]), ) ) @@ -1075,9 +1063,9 @@ def test_stage_item(self, tmp_path: Path): # Act with change_cwd(tmp_path), files_manager(): remove_bitbucket_step_from_default( - Step( + schema.Step( name="Farewell", - script=Script(["echo 'Goodbye!'"]), + script=schema.Script(["echo 'Goodbye!'"]), ) ) @@ -1123,9 +1111,9 @@ def test_remove_stage_item_leaving_placeholder(self, uv_init_dir: Path): # Act with change_cwd(uv_init_dir), files_manager(): remove_bitbucket_step_from_default( - Step( + schema.Step( name="Farewell", - script=Script(["echo 'Goodbye!'"]), + script=schema.Script(["echo 'Goodbye!'"]), ) ) @@ -1161,8 +1149,8 @@ class TestGetStepsInPipelineItem: class TestStepItem: def test_step(self): # Arrange - step = Step(script=Script(["echo 'Hello, world!'"])) - item = StepItem(step=step) + step = schema.Step(script=schema.Script(["echo 'Hello, world!'"])) + item = schema.StepItem(step=step) # Act steps = get_steps_in_pipeline_item(item) @@ -1174,12 +1162,14 @@ class TestParallelItem: def test_parallel_steps(self): # Arrange original_steps = [ - Step(script=Script(["echo 'Hello, world!'"])), - Step(script=Script(["echo 'Why, hello!'"])), + schema.Step(script=schema.Script(["echo 'Hello, world!'"])), + schema.Step(script=schema.Script(["echo 'Why, hello!'"])), ] - item = ParallelItem( - parallel=Parallel( - ParallelSteps([StepItem(step=step) for step in original_steps]) + item = schema.ParallelItem( + parallel=schema.Parallel( + schema.ParallelSteps( + [schema.StepItem(step=step) for step in original_steps] + ) ) ) @@ -1192,14 +1182,14 @@ def test_parallel_steps(self): def test_parallel_expanded(self): # Arrange original_steps = [ - Step(script=Script(["echo 'Hello, world!'"])), - Step(script=Script(["echo 'Why, hello!'"])), + schema.Step(script=schema.Script(["echo 'Hello, world!'"])), + schema.Step(script=schema.Script(["echo 'Why, hello!'"])), ] - item = ParallelItem( - parallel=Parallel( - ParallelExpanded( - steps=ParallelSteps( - [StepItem(step=step) for step in original_steps] + item = schema.ParallelItem( + parallel=schema.Parallel( + schema.ParallelExpanded( + steps=schema.ParallelSteps( + [schema.StepItem(step=step) for step in original_steps] ) ) ) @@ -1214,14 +1204,14 @@ def test_parallel_expanded(self): class TestStageItem: def test_steps(self): # Arrange - script = Script(["echo 'Hello, world!'"]) - item = StageItem( - stage=Stage( + script = schema.Script(["echo 'Hello, world!'"]) + item = schema.StageItem( + stage=schema.Stage( steps=[ - Step1( - step=Step2( + schema.Step1( + step=schema.Step2( name="greetings", - script=Script(["echo 'Hello, world!'"]), + script=schema.Script(["echo 'Hello, world!'"]), ) ), ] @@ -1232,7 +1222,7 @@ def test_steps(self): steps = get_steps_in_pipeline_item(item) # Assert - assert steps == [Step(name="greetings", script=script)] + assert steps == [schema.Step(name="greetings", script=script)] class TestAddPlaceholderStepInDefault: @@ -1433,10 +1423,10 @@ def test_unrecognized(self, tmp_path: Path): model = mgr.model_validate() with pytest.raises(NotImplementedError, match=match): _add_step_caches_via_model( - step=Step( + step=schema.Step( name="Greeting", caches=["unrecognized"], - script=Script(["echo 'Hello, world!'"]), + script=schema.Script(["echo 'Hello, world!'"]), ), model=model, ) @@ -1445,13 +1435,13 @@ def test_unrecognized(self, tmp_path: Path): class TestStepsAreEquivalent: def test_identical(self): # Arrange - step = Step( + step = schema.Step( name="Greeting", - script=Script(["echo 'Hello, world!'"]), + script=schema.Script(["echo 'Hello, world!'"]), ) - other = Step( + other = schema.Step( name="Greeting", - script=Script(["echo 'Hello, world!'"]), + script=schema.Script(["echo 'Hello, world!'"]), ) # Act @@ -1462,13 +1452,13 @@ def test_identical(self): def test_different_name(self): # Arrange - step = Step( + step = schema.Step( name="Greeting", - script=Script(["echo 'Hello, world!'"]), + script=schema.Script(["echo 'Hello, world!'"]), ) - other = Step( + other = schema.Step( name="Farewell", - script=Script(["echo 'Hello, world!'"]), + script=schema.Script(["echo 'Hello, world!'"]), ) # Act @@ -1479,13 +1469,13 @@ def test_different_name(self): def test_different_script(self): # Arrange - step = Step( + step = schema.Step( name="Greeting", - script=Script(["echo 'Hello, world!'"]), + script=schema.Script(["echo 'Hello, world!'"]), ) - other = Step( + other = schema.Step( name="Greeting", - script=Script(["echo 'Goodbye!'"]), + script=schema.Script(["echo 'Goodbye!'"]), ) # Act @@ -1496,13 +1486,13 @@ def test_different_script(self): def test_case_sensitive_name_difference(self): # Arrange - step = Step( + step = schema.Step( name="Greeting", - script=Script(["echo 'Hello, world!'"]), + script=schema.Script(["echo 'Hello, world!'"]), ) - other = Step( + other = schema.Step( name="greeting", - script=Script(["echo 'See ya!'"]), + script=schema.Script(["echo 'See ya!'"]), ) # Act @@ -1514,9 +1504,9 @@ def test_case_sensitive_name_difference(self): def test_none(self): # Arrange step = None - other = Step( + other = schema.Step( name="Greeting", - script=Script(["echo 'Hello, world!'"]), + script=schema.Script(["echo 'Hello, world!'"]), ) # Act @@ -1604,9 +1594,9 @@ def test_default_pipeline(self, tmp_path: Path): # Assert assert steps == [ - Step( + schema.Step( name="Greeting", - script=Script(["echo 'Hello, world!'"]), + script=schema.Script(["echo 'Hello, world!'"]), ) ] diff --git a/tests/usethis/_integrations/ci/bitbucket/test_yaml.py b/tests/usethis/_integrations/ci/bitbucket/test_yaml.py index 072abd18..66085419 100644 --- a/tests/usethis/_integrations/ci/bitbucket/test_yaml.py +++ b/tests/usethis/_integrations/ci/bitbucket/test_yaml.py @@ -2,16 +2,8 @@ import pytest +from usethis._integrations.ci.bitbucket import schema from usethis._integrations.ci.bitbucket.errors import BitbucketPipelinesYAMLSchemaError -from usethis._integrations.ci.bitbucket.schema import ( - Cache, - CachePath, - Clone, - Definitions, - Image, - ImageName, - PipelinesConfiguration, -) from usethis._integrations.ci.bitbucket.yaml import ( ORDER_BY_CLS, BitbucketPipelinesYAMLManager, @@ -191,12 +183,12 @@ def test_attribute_consistency(self): class TestBitbucketFancyDump: def test_order(self): # Arrange - config = PipelinesConfiguration( - image=Image(ImageName("python:3.8.1")), - clone=Clone(depth="full"), - definitions=Definitions( + config = schema.PipelinesConfiguration( + image=schema.Image(schema.ImageName("python:3.8.1")), + clone=schema.Clone(depth="full"), + definitions=schema.Definitions( caches={ - "pip": Cache(CachePath("pip")), + "pip": schema.Cache(schema.CachePath("pip")), }, ), ) diff --git a/tests/usethis/_integrations/pre_commit/test_hooks.py b/tests/usethis/_integrations/pre_commit/test_hooks.py index 108ca884..bcfbda12 100644 --- a/tests/usethis/_integrations/pre_commit/test_hooks.py +++ b/tests/usethis/_integrations/pre_commit/test_hooks.py @@ -3,6 +3,7 @@ import pytest from usethis._config_file import files_manager +from usethis._integrations.pre_commit import schema from usethis._integrations.pre_commit.hooks import ( _get_placeholder_repo_config, add_placeholder_hook, @@ -12,12 +13,6 @@ insert_repo, remove_hook, ) -from usethis._integrations.pre_commit.schema import ( - HookDefinition, - Language, - LocalRepo, - UriRepo, -) from usethis._integrations.pre_commit.yaml import PreCommitConfigYAMLManager from usethis._test import change_cwd @@ -36,8 +31,10 @@ def test_unregistered_id(self, tmp_path: Path): pytest.raises(NotImplementedError, match="Hook 'foo' not recognized"), ): add_repo( - UriRepo( - repo="foo", rev="foo", hooks=[HookDefinition(id="foo", name="foo")] + schema.UriRepo( + repo="foo", + rev="foo", + hooks=[schema.HookDefinition(id="foo", name="foo")], ) ) @@ -55,14 +52,14 @@ def test_adding_to_existing( # Act with change_cwd(tmp_path), files_manager(): add_repo( - LocalRepo( + schema.LocalRepo( repo="local", hooks=[ - HookDefinition( + schema.HookDefinition( id="deptry", name="deptry", entry="uv run --frozen deptry src", - language=Language("system"), + language=schema.Language("system"), always_run=True, ) ], @@ -119,14 +116,14 @@ def test_hook_order_constant_is_respected(self, tmp_path: Path): with change_cwd(tmp_path), files_manager(): # Arrange: Add 'codespell' first (later in _HOOK_ORDER) add_repo( - LocalRepo( + schema.LocalRepo( repo="local", hooks=[ - HookDefinition( + schema.HookDefinition( id="codespell", name="codespell", entry="codespell .", - language=Language("system"), + language=schema.Language("system"), ) ], ) @@ -134,14 +131,14 @@ def test_hook_order_constant_is_respected(self, tmp_path: Path): # Now add 'pyproject-fmt' (earlier in _HOOK_ORDER) add_repo( - LocalRepo( + schema.LocalRepo( repo="local", hooks=[ - HookDefinition( + schema.HookDefinition( id="pyproject-fmt", name="pyproject-fmt", entry="uv run --frozen pyproject-fmt .", - language=Language("system"), + language=schema.Language("system"), ) ], ) @@ -157,14 +154,14 @@ def test_hooks_added_in_standard_order(self, tmp_path: Path): with change_cwd(tmp_path), files_manager(): # Arrange add_repo( - LocalRepo( + schema.LocalRepo( repo="local", hooks=[ - HookDefinition( + schema.HookDefinition( id="pyproject-fmt", name="pyproject-fmt", entry="uv run --frozen pyproject-fmt .", - language=Language("system"), + language=schema.Language("system"), ) ], ) @@ -172,14 +169,14 @@ def test_hooks_added_in_standard_order(self, tmp_path: Path): # Act add_repo( - LocalRepo( + schema.LocalRepo( repo="local", hooks=[ - HookDefinition( + schema.HookDefinition( id="codespell", name="codespell", entry="codespell .", - language=Language("system"), + language=schema.Language("system"), ) ], ) @@ -194,40 +191,40 @@ def test_hook_order_constant_is_respected_multi(self, tmp_path: Path): with change_cwd(tmp_path), files_manager(): # Act add_repo( - LocalRepo( + schema.LocalRepo( repo="local", hooks=[ - HookDefinition( + schema.HookDefinition( id="foo", name="foo", entry="foo .", - language=Language("system"), + language=schema.Language("system"), ) ], ), ) add_repo( - LocalRepo( + schema.LocalRepo( repo="local", hooks=[ - HookDefinition( + schema.HookDefinition( id="codespell", name="codespell", entry="codespell .", - language=Language("system"), + language=schema.Language("system"), ) ], ) ) add_repo( - LocalRepo( + schema.LocalRepo( repo="local", hooks=[ - HookDefinition( + schema.HookDefinition( id="pyproject-fmt", name="pyproject-fmt", entry="uv run --frozen pyproject-fmt .", - language=Language("system"), + language=schema.Language("system"), ) ], ) @@ -257,14 +254,14 @@ def test_predecessor_is_none( with change_cwd(tmp_path), PreCommitConfigYAMLManager() as mgr: existing_repos = mgr.model_validate().repos repos = insert_repo( - repo_to_insert=LocalRepo( + repo_to_insert=schema.LocalRepo( repo="local", hooks=[ - HookDefinition( + schema.HookDefinition( id="pyproject-fmt", name="pyproject-fmt", entry="uv run --frozen pyproject-fmt .", - language=Language("system"), + language=schema.Language("system"), ) ], ), @@ -282,14 +279,14 @@ def test_predecessor_is_none( def test_existing_repo_has_none_hooks(self): # Arrange - existing_repos = [LocalRepo(repo="local", hooks=None)] - new_hook = HookDefinition( + existing_repos = [schema.LocalRepo(repo="local", hooks=None)] + new_hook = schema.HookDefinition( id="new-hook", name="New Hook", entry="echo 'New hook'", - language=Language("system"), + language=schema.Language("system"), ) - repo_to_insert = LocalRepo( + repo_to_insert = schema.LocalRepo( repo="local", hooks=[new_hook], ) @@ -305,8 +302,8 @@ def test_existing_repo_has_none_hooks(self): assert isinstance(results, list) assert len(results) == 2 assert results == [ - LocalRepo(repo="local", hooks=[new_hook]), - LocalRepo(repo="local", hooks=None), + schema.LocalRepo(repo="local", hooks=[new_hook]), + schema.LocalRepo(repo="local", hooks=None), ] def test_duplicate_predecessor( @@ -329,14 +326,14 @@ def test_duplicate_predecessor( with change_cwd(tmp_path), PreCommitConfigYAMLManager() as mgr: existing_repos = mgr.model_validate().repos repos = insert_repo( - repo_to_insert=LocalRepo( + repo_to_insert=schema.LocalRepo( repo="local", hooks=[ - HookDefinition( + schema.HookDefinition( id="pyproject-fmt", name="pyproject-fmt", entry="uv run --frozen pyproject-fmt .", - language=Language("system"), + language=schema.Language("system"), ) ], ), @@ -548,17 +545,17 @@ def test_contents(self, tmp_path: Path, capfd: pytest.CaptureFixture[str]): class TestHooksAreEquivalent: def test_identical(self): # Arrange - hook = HookDefinition( + hook = schema.HookDefinition( id="foo", name="Foo", entry="echo 'Hello, world!'", - language=Language("python"), + language=schema.Language("python"), ) - other = HookDefinition( + other = schema.HookDefinition( id="foo", name="Foo", entry="echo 'Hello, world!'", - language=Language("python"), + language=schema.Language("python"), ) # Act @@ -569,17 +566,17 @@ def test_identical(self): def test_different_id(self): # Arrange - hook = HookDefinition( + hook = schema.HookDefinition( id="foo", name="Foo", entry="echo 'Hello, world!'", - language=Language("python"), + language=schema.Language("python"), ) - other = HookDefinition( + other = schema.HookDefinition( id="bar", name="Foo", entry="echo 'Hello, world!'", - language=Language("python"), + language=schema.Language("python"), ) # Act @@ -590,17 +587,17 @@ def test_different_id(self): def test_different_name(self): # Arrange - hook = HookDefinition( + hook = schema.HookDefinition( id="foo", name="Foo", entry="echo 'Hello, world!'", - language=Language("python"), + language=schema.Language("python"), ) - other = HookDefinition( + other = schema.HookDefinition( id="foo", name="Bar", entry="echo 'Hello, world!'", - language=Language("python"), + language=schema.Language("python"), ) # Act @@ -611,12 +608,12 @@ def test_different_name(self): def test_case_sensitive_id_difference(self): # Arrange - hook = HookDefinition( + hook = schema.HookDefinition( id="foo", name="Foo", entry="echo 'Hello, world!'", ) - other = HookDefinition( + other = schema.HookDefinition( id="FOO", name="Different", entry="echo 'Au revoir!'", @@ -630,17 +627,17 @@ def test_case_sensitive_id_difference(self): def test_no_id(self): # Arrange - hook = HookDefinition( + hook = schema.HookDefinition( id=None, name="Foo", entry="echo 'Hello, world!'", - language=Language("python"), + language=schema.Language("python"), ) - other = HookDefinition( + other = schema.HookDefinition( id="foo", name="Foo", entry="echo 'Hello, world!'", - language=Language("python"), + language=schema.Language("python"), ) # Act @@ -652,10 +649,10 @@ def test_no_id(self): def test_aliases(self): # Arrange / Act / Assert assert hooks_are_equivalent( - HookDefinition(id="ruff"), - HookDefinition(id="ruff-check"), + schema.HookDefinition(id="ruff"), + schema.HookDefinition(id="ruff-check"), ) assert hooks_are_equivalent( - HookDefinition(id="ruff-check"), - HookDefinition(id="ruff"), + schema.HookDefinition(id="ruff-check"), + schema.HookDefinition(id="ruff"), ) diff --git a/tests/usethis/_integrations/pre_commit/test_language.py b/tests/usethis/_integrations/pre_commit/test_language.py index 9ca3dcaf..4354bd56 100644 --- a/tests/usethis/_integrations/pre_commit/test_language.py +++ b/tests/usethis/_integrations/pre_commit/test_language.py @@ -1,8 +1,8 @@ from pathlib import Path from usethis._config_file import files_manager +from usethis._integrations.pre_commit import schema from usethis._integrations.pre_commit.language import get_system_language -from usethis._integrations.pre_commit.schema import Language from usethis._test import change_cwd @@ -23,7 +23,7 @@ def test_returns_unsupported_when_minimum_version_is_4_4_0(self, tmp_path: Path) result = get_system_language() # Assert - assert result == Language("unsupported") + assert result == schema.Language("unsupported") def test_returns_unsupported_when_minimum_version_is_above_4_4_0( self, tmp_path: Path @@ -43,7 +43,7 @@ def test_returns_unsupported_when_minimum_version_is_above_4_4_0( result = get_system_language() # Assert - assert result == Language("unsupported") + assert result == schema.Language("unsupported") def test_returns_system_when_minimum_version_is_below_4_4_0(self, tmp_path: Path): # Arrange @@ -61,7 +61,7 @@ def test_returns_system_when_minimum_version_is_below_4_4_0(self, tmp_path: Path result = get_system_language() # Assert - assert result == Language("system") + assert result == schema.Language("system") def test_returns_system_when_config_doesnt_exist(self, tmp_path: Path): # Act @@ -69,7 +69,7 @@ def test_returns_system_when_config_doesnt_exist(self, tmp_path: Path): result = get_system_language() # Assert - assert result == Language("system") + assert result == schema.Language("system") def test_returns_system_when_minimum_version_not_declared(self, tmp_path: Path): # Arrange @@ -86,7 +86,7 @@ def test_returns_system_when_minimum_version_not_declared(self, tmp_path: Path): result = get_system_language() # Assert - assert result == Language("system") + assert result == schema.Language("system") def test_returns_system_when_minimum_version_is_3_x(self, tmp_path: Path): # Arrange @@ -104,4 +104,4 @@ def test_returns_system_when_minimum_version_is_3_x(self, tmp_path: Path): result = get_system_language() # Assert - assert result == Language("system") + assert result == schema.Language("system") diff --git a/tests/usethis/_integrations/pre_commit/test_pre_commit_schema.py b/tests/usethis/_integrations/pre_commit/test_pre_commit_schema.py index 60c82c37..497bb344 100644 --- a/tests/usethis/_integrations/pre_commit/test_pre_commit_schema.py +++ b/tests/usethis/_integrations/pre_commit/test_pre_commit_schema.py @@ -9,17 +9,17 @@ from usethis._integrations.file.pyproject_toml.requires_python import ( get_requires_python, ) -from usethis._integrations.pre_commit.schema import HookDefinition, LocalRepo +from usethis._integrations.pre_commit import schema from usethis._test import change_cwd, is_offline def test_multiple_per_repo(): # There was a suspicion this wasn't possible, but it is. - LocalRepo( + schema.LocalRepo( repo="local", hooks=[ - HookDefinition(id="black"), - HookDefinition(id="isort"), + schema.HookDefinition(id="black"), + schema.HookDefinition(id="isort"), ], ) diff --git a/tests/usethis/_integrations/pre_commit/test_yaml.py b/tests/usethis/_integrations/pre_commit/test_yaml.py index c49db789..0ec8ec72 100644 --- a/tests/usethis/_integrations/pre_commit/test_yaml.py +++ b/tests/usethis/_integrations/pre_commit/test_yaml.py @@ -4,11 +4,9 @@ import pytest from usethis._config_file import files_manager +from usethis._integrations.pre_commit import schema from usethis._integrations.pre_commit.errors import PreCommitConfigYAMLConfigError from usethis._integrations.pre_commit.hooks import _get_placeholder_repo_config -from usethis._integrations.pre_commit.schema import ( - JsonSchemaForPreCommitConfigYaml, -) from usethis._integrations.pre_commit.yaml import ( PreCommitConfigYAMLManager, _pre_commit_fancy_dump, @@ -143,7 +141,7 @@ def test_placeholder(self, tmp_path: Path): # Act with change_cwd(tmp_path), files_manager(): _pre_commit_fancy_dump( - config=JsonSchemaForPreCommitConfigYaml( + config=schema.JsonSchemaForPreCommitConfigYaml( repos=[ _get_placeholder_repo_config(), ] diff --git a/tests/usethis/_tool/impl/test_codespell.py b/tests/usethis/_tool/impl/test_codespell.py index bfc78116..843dcf46 100644 --- a/tests/usethis/_tool/impl/test_codespell.py +++ b/tests/usethis/_tool/impl/test_codespell.py @@ -7,7 +7,7 @@ from usethis._config_file import files_manager from usethis._integrations.ci.github.errors import GitHubTagError from usethis._integrations.ci.github.tags import get_github_latest_tag -from usethis._integrations.pre_commit.schema import UriRepo +from usethis._integrations.pre_commit import schema from usethis._test import change_cwd from usethis._tool.impl.codespell import CodespellTool from usethis._types.backend import BackendEnum @@ -143,7 +143,7 @@ def test_latest_version(self): (config,) = CodespellTool().get_pre_commit_config().repo_configs repo = config.repo - assert isinstance(repo, UriRepo) + assert isinstance(repo, schema.UriRepo) try: assert repo.rev == get_github_latest_tag( owner="codespell-project", repo="codespell" diff --git a/tests/usethis/_tool/impl/test_deptry.py b/tests/usethis/_tool/impl/test_deptry.py index 02d1d21d..cb4b8ace 100644 --- a/tests/usethis/_tool/impl/test_deptry.py +++ b/tests/usethis/_tool/impl/test_deptry.py @@ -4,7 +4,7 @@ from usethis._config_file import files_manager from usethis._integrations.file.pyproject_toml.io_ import PyprojectTOMLManager -from usethis._integrations.pre_commit.schema import Language +from usethis._integrations.pre_commit import schema from usethis._test import change_cwd from usethis._tool.config import ConfigEntry, ConfigItem from usethis._tool.impl.deptry import DeptryTool @@ -288,7 +288,9 @@ def test_uses_system_language_when_no_minimum_version(self, tmp_path: Path): # Assert assert result.repo_configs is not None assert result.repo_configs[0].repo.hooks is not None - assert result.repo_configs[0].repo.hooks[0].language == Language("system") + assert result.repo_configs[0].repo.hooks[0].language == schema.Language( + "system" + ) def test_uses_system_language_when_minimum_version_below_4_4_0( self, tmp_path: Path @@ -313,7 +315,9 @@ def test_uses_system_language_when_minimum_version_below_4_4_0( # Assert assert result.repo_configs is not None assert result.repo_configs[0].repo.hooks is not None - assert result.repo_configs[0].repo.hooks[0].language == Language("system") + assert result.repo_configs[0].repo.hooks[0].language == schema.Language( + "system" + ) def test_uses_unsupported_language_when_minimum_version_is_4_4_0( self, tmp_path: Path @@ -338,7 +342,7 @@ def test_uses_unsupported_language_when_minimum_version_is_4_4_0( # Assert assert result.repo_configs is not None assert result.repo_configs[0].repo.hooks is not None - assert result.repo_configs[0].repo.hooks[0].language == Language( + assert result.repo_configs[0].repo.hooks[0].language == schema.Language( "unsupported" ) @@ -365,6 +369,6 @@ def test_uses_unsupported_language_when_minimum_version_above_4_4_0( # Assert assert result.repo_configs is not None assert result.repo_configs[0].repo.hooks is not None - assert result.repo_configs[0].repo.hooks[0].language == Language( + assert result.repo_configs[0].repo.hooks[0].language == schema.Language( "unsupported" ) diff --git a/tests/usethis/_tool/impl/test_pre_commit.py b/tests/usethis/_tool/impl/test_pre_commit.py index dcdcadcd..2d72caf9 100644 --- a/tests/usethis/_tool/impl/test_pre_commit.py +++ b/tests/usethis/_tool/impl/test_pre_commit.py @@ -7,7 +7,7 @@ from usethis._config_file import files_manager from usethis._integrations.ci.github.errors import GitHubTagError from usethis._integrations.ci.github.tags import get_github_latest_tag -from usethis._integrations.pre_commit.schema import UriRepo +from usethis._integrations.pre_commit import schema from usethis._integrations.pre_commit.version import PRE_COMMIT_VERSION from usethis._test import change_cwd from usethis._tool.impl.pre_commit import PreCommitTool @@ -44,7 +44,7 @@ def test_latest_sync_with_uv_version(self, tmp_path: Path): with change_cwd(tmp_path), files_manager(): (config,) = PreCommitTool().get_pre_commit_config().repo_configs repo = config.repo - assert isinstance(repo, UriRepo) + assert isinstance(repo, schema.UriRepo) try: assert repo.rev == get_github_latest_tag( owner="tsvikas", repo="sync-with-uv" diff --git a/tests/usethis/_tool/impl/test_pyproject_fmt.py b/tests/usethis/_tool/impl/test_pyproject_fmt.py index bdfc82f7..9422440f 100644 --- a/tests/usethis/_tool/impl/test_pyproject_fmt.py +++ b/tests/usethis/_tool/impl/test_pyproject_fmt.py @@ -7,7 +7,7 @@ from usethis._config_file import files_manager from usethis._integrations.ci.github.errors import GitHubTagError from usethis._integrations.ci.github.tags import get_github_latest_tag -from usethis._integrations.pre_commit.schema import UriRepo +from usethis._integrations.pre_commit import schema from usethis._test import change_cwd from usethis._tool.impl.pyproject_fmt import PyprojectFmtTool @@ -36,7 +36,7 @@ def test_latest_version(self): (config,) = PyprojectFmtTool().get_pre_commit_config().repo_configs repo = config.repo - assert isinstance(repo, UriRepo) + assert isinstance(repo, schema.UriRepo) try: # N.B. this is the pre-commit mirror, it can lag behind the main repo # at https://github.com/tox-dev/toml-fmt/tree/main/pyproject-fmt diff --git a/tests/usethis/_tool/impl/test_ruff.py b/tests/usethis/_tool/impl/test_ruff.py index da15c704..e5282717 100644 --- a/tests/usethis/_tool/impl/test_ruff.py +++ b/tests/usethis/_tool/impl/test_ruff.py @@ -9,7 +9,7 @@ from usethis._integrations.ci.github.errors import GitHubTagError from usethis._integrations.ci.github.tags import get_github_latest_tag from usethis._integrations.file.pyproject_toml.io_ import PyprojectTOMLManager -from usethis._integrations.pre_commit.schema import UriRepo +from usethis._integrations.pre_commit import schema from usethis._test import change_cwd from usethis._tool.impl.ruff import RuffTool @@ -384,7 +384,7 @@ def test_latest_version(self, tmp_path: Path): # Act (config,) = RuffTool().get_pre_commit_config().repo_configs repo = config.repo - assert isinstance(repo, UriRepo) + assert isinstance(repo, schema.UriRepo) try: assert repo.rev == get_github_latest_tag( owner="astral-sh", repo="ruff-pre-commit" diff --git a/tests/usethis/_tool/test_base.py b/tests/usethis/_tool/test_base.py index e59ef011..83f81ff8 100644 --- a/tests/usethis/_tool/test_base.py +++ b/tests/usethis/_tool/test_base.py @@ -8,8 +8,8 @@ from usethis._deps import add_deps_to_group from usethis._integrations.file.pyproject_toml.io_ import PyprojectTOMLManager from usethis._integrations.file.setup_cfg.io_ import SetupCFGManager +from usethis._integrations.pre_commit import schema from usethis._integrations.pre_commit.hooks import _PLACEHOLDER_ID, get_hook_ids -from usethis._integrations.pre_commit.schema import HookDefinition, UriRepo from usethis._io import KeyValueFileManager from usethis._test import change_cwd from usethis._tool.base import Tool @@ -58,9 +58,9 @@ def get_dev_deps(self, *, unconditional: bool = False) -> list[Dependency]: def get_pre_commit_config(self) -> PreCommitConfig: return PreCommitConfig.from_single_repo( - UriRepo( + schema.UriRepo( repo=f"repo for {self.name}", - hooks=[HookDefinition(id="deptry")], + hooks=[schema.HookDefinition(id="deptry")], ), requires_venv=False, ) @@ -102,11 +102,11 @@ def print_how_to_use(self) -> None: def get_pre_commit_config(self) -> PreCommitConfig: return PreCommitConfig.from_single_repo( - UriRepo( + schema.UriRepo( repo=f"repo for {self.name}", hooks=[ - HookDefinition(id="ruff"), - HookDefinition(id="ruff-format"), + schema.HookDefinition(id="ruff"), + schema.HookDefinition(id="ruff-format"), ], ), requires_venv=False, @@ -157,7 +157,9 @@ def test_default(self): def test_specific(self): tool = MyTool() assert tool.get_pre_commit_repos() == [ - UriRepo(repo="repo for my_tool", hooks=[HookDefinition(id="deptry")]) + schema.UriRepo( + repo="repo for my_tool", hooks=[schema.HookDefinition(id="deptry")] + ) ] class TestGetConfigSpec: @@ -512,20 +514,20 @@ def get_pre_commit_config(self) -> PreCommitConfig: return PreCommitConfig( repo_configs=[ PreCommitRepoConfig( - repo=UriRepo( + repo=schema.UriRepo( repo="example", hooks=[ - HookDefinition(id="ruff"), - HookDefinition(id="ruff-format"), + schema.HookDefinition(id="ruff"), + schema.HookDefinition(id="ruff-format"), ], ), requires_venv=False, ), PreCommitRepoConfig( - repo=UriRepo( + repo=schema.UriRepo( repo="other", hooks=[ - HookDefinition( + schema.HookDefinition( id="deptry", ) ], @@ -819,20 +821,20 @@ def get_pre_commit_config(self) -> PreCommitConfig: return PreCommitConfig( repo_configs=[ PreCommitRepoConfig( - repo=UriRepo( + repo=schema.UriRepo( repo="example", hooks=[ - HookDefinition(id="ruff"), - HookDefinition(id="ruff-format"), + schema.HookDefinition(id="ruff"), + schema.HookDefinition(id="ruff-format"), ], ), requires_venv=False, ), PreCommitRepoConfig( - repo=UriRepo( + repo=schema.UriRepo( repo="other", hooks=[ - HookDefinition( + schema.HookDefinition( id="deptry", ) ],