diff --git a/CHANGES/726.misc b/CHANGES/726.misc new file mode 100644 index 000000000..6891eb427 --- /dev/null +++ b/CHANGES/726.misc @@ -0,0 +1 @@ +Adjusted to typing improvements in click>=8.1.4. diff --git a/pulpcore/cli/ansible/content.py b/pulpcore/cli/ansible/content.py index eba5d7f28..0525948e1 100644 --- a/pulpcore/cli/ansible/content.py +++ b/pulpcore/cli/ansible/content.py @@ -1,4 +1,4 @@ -from typing import IO, Any, Callable, Optional, Union +from typing import IO, Any, Callable, Optional import click from pulp_glue.ansible.context import ( @@ -218,7 +218,9 @@ def content(ctx: click.Context, pulp_ctx: PulpCLIContext, content_type: str) -> content.add_command(show_command(decorators=lookup_options)) -@content.command() +# This is a mypy bug getting confused with positional args +# https://github.com/python/mypy/issues/15037 +@content.command() # type: ignore [arg-type] @click.option("--file", type=click.File("rb"), required=True) @repository_option @pulp_option( @@ -253,11 +255,7 @@ def content(ctx: click.Context, pulp_ctx: PulpCLIContext, content_type: str) -> @pass_pulp_context def upload( pulp_ctx: PulpCLIContext, - content_ctx: Union[ - PulpAnsibleRoleContext, - PulpAnsibleCollectionVersionContext, - PulpAnsibleCollectionVersionSignatureContext, - ], + content_ctx: PulpEntityContext, file: IO[bytes], **kwargs: Any, ) -> None: diff --git a/pulpcore/cli/ansible/distribution.py b/pulpcore/cli/ansible/distribution.py index 852a79013..103181382 100644 --- a/pulpcore/cli/ansible/distribution.py +++ b/pulpcore/cli/ansible/distribution.py @@ -7,6 +7,7 @@ EntityFieldDefinition, PluginRequirement, PulpContext, + PulpEntityContext, ) from pulp_glue.common.i18n import get_translation @@ -104,7 +105,7 @@ def distribution(ctx: click.Context, pulp_ctx: PulpContext, distribution_type: s @pulp_labels_option @pass_entity_context def update( - distribution_ctx: PulpAnsibleDistributionContext, + distribution_ctx: PulpEntityContext, base_path: Optional[str], repository: EntityFieldDefinition, content_guard: EntityFieldDefinition, @@ -114,6 +115,8 @@ def update( """ To remove repository or repository_version fields set --repository to "" """ + assert isinstance(distribution_ctx, PulpAnsibleDistributionContext) + dist_body: EntityDefinition = distribution_ctx.entity name: str = dist_body["name"] body: EntityDefinition = dict() diff --git a/pulpcore/cli/common/config.py b/pulpcore/cli/common/config.py index 731906973..f88502e5e 100644 --- a/pulpcore/cli/common/config.py +++ b/pulpcore/cli/common/config.py @@ -143,7 +143,9 @@ def config() -> None: pass -@config.command(help=_("Create a pulp-cli config settings file")) +# This is a mypy bug getting confused with positional args +# https://github.com/python/mypy/issues/15037 +@config.command(help=_("Create a pulp-cli config settings file")) # type: ignore [arg-type] @config_options @click.option("--interactive", "-i", is_flag=True) @click.option("--editor", "-e", is_flag=True, help=_("Edit the config file in an editor")) diff --git a/pulpcore/cli/common/generic.py b/pulpcore/cli/common/generic.py index fd8b636d1..5a49616b0 100644 --- a/pulpcore/cli/common/generic.py +++ b/pulpcore/cli/common/generic.py @@ -1,13 +1,12 @@ import datetime import json import re +import typing as t from functools import lru_cache, wraps -from typing import IO, Any, Callable, Dict, Iterable, List, Mapping, Optional, Tuple, Type, Union import click import schema as s import yaml -from click.decorators import FC, F from pulp_glue.common.context import ( DATETIME_FORMATS, DEFAULT_LIMIT, @@ -42,6 +41,10 @@ _ = translation.gettext +_AnyCallable = t.Callable[..., t.Any] +FC = t.TypeVar("FC", bound=t.Union[_AnyCallable, click.Command]) + + class IncompatibleContext(click.UsageError): pass @@ -49,7 +52,7 @@ class IncompatibleContext(click.UsageError): class ClickNoWait(click.ClickException): exit_code = 0 - def show(self, file: Optional[IO[str]] = None) -> None: + def show(self, file: t.Optional[t.IO[str]] = None) -> None: """ Format the message into file or STDERR. Overwritten from base class to not print "Error: ". @@ -60,7 +63,7 @@ def show(self, file: Optional[IO[str]] = None) -> None: class PulpJSONEncoder(json.JSONEncoder): - def default(self, obj: Any) -> Any: + def default(self, obj: t.Any) -> t.Any: if isinstance(obj, datetime.datetime): return obj.isoformat() else: @@ -75,7 +78,7 @@ class PulpCLIContext(PulpContext): def __init__( self, api_root: str, - api_kwargs: Dict[str, Any], + api_kwargs: t.Dict[str, t.Any], background_tasks: bool, timeout: int, format: str, @@ -93,10 +96,10 @@ def __init__( def echo(self, message: str, nl: bool = True, err: bool = False) -> None: click.echo(message, nl=nl, err=err) - def prompt(self, text: str, hide_input: bool = False) -> Any: + def prompt(self, text: str, hide_input: bool = False) -> t.Any: return click.prompt(text, hide_input=hide_input) - def output_result(self, result: Any) -> None: + def output_result(self, result: t.Any) -> None: """ Dump the provided result to the console using the selected renderer """ @@ -124,16 +127,17 @@ def output_result(self, result: Any) -> None: pass_pulp_context = click.make_pass_decorator(PulpCLIContext) pass_entity_context = click.make_pass_decorator(PulpEntityContext) +pass_acs_context = click.make_pass_decorator(PulpACSContext) +pass_content_context = click.make_pass_decorator(PulpContentContext) pass_repository_context = click.make_pass_decorator(PulpRepositoryContext) pass_repository_version_context = click.make_pass_decorator(PulpRepositoryVersionContext) -pass_content_context = click.make_pass_decorator(PulpContentContext) ############################################################################## # Custom types for parameters -def int_or_empty(value: str) -> Union[str, int]: +def int_or_empty(value: str) -> t.Union[str, int]: if value == "": return "" else: @@ -143,7 +147,7 @@ def int_or_empty(value: str) -> Union[str, int]: int_or_empty.__name__ = "int or empty" -def float_or_empty(value: str) -> Union[str, float]: +def float_or_empty(value: str) -> t.Union[str, float]: if value == "": return "" else: @@ -160,16 +164,16 @@ def float_or_empty(value: str) -> Union[str, float]: class PulpCommand(click.Command): def __init__( self, - *args: Any, - allowed_with_contexts: Optional[Tuple[Type[PulpEntityContext]]] = None, - needs_plugins: Optional[List[PluginRequirement]] = None, - **kwargs: Any, + *args: t.Any, + allowed_with_contexts: t.Optional[t.Tuple[t.Type[PulpEntityContext]]] = None, + needs_plugins: t.Optional[t.List[PluginRequirement]] = None, + **kwargs: t.Any, ): self.allowed_with_contexts = allowed_with_contexts self.needs_plugins = needs_plugins super().__init__(*args, **kwargs) - def invoke(self, ctx: click.Context) -> Any: + def invoke(self, ctx: click.Context) -> t.Any: try: if self.needs_plugins: pulp_ctx = ctx.find_object(PulpCLIContext) @@ -194,9 +198,9 @@ def format_help_text( self.help = self.help.format(entity=entity_ctx.ENTITY, entities=entity_ctx.ENTITIES) super().format_help_text(ctx, formatter) - def get_params(self, ctx: click.Context) -> List[click.Parameter]: + def get_params(self, ctx: click.Context) -> t.List[click.Parameter]: params = super().get_params(ctx) - new_params: List[click.Parameter] = [] + new_params: t.List[click.Parameter] = [] for param in params: if isinstance(param, PulpOption): if param.allowed_with_contexts is not None: @@ -210,7 +214,7 @@ class PulpGroup(PulpCommand, click.Group): command_class = PulpCommand group_class = type - def get_command(self, ctx: click.Context, cmd_name: str) -> Optional[click.Command]: + def get_command(self, ctx: click.Context, cmd_name: str) -> t.Optional[click.Command]: # Overwriting this removes the command from the help message and from being callable cmd = super().get_command(ctx, cmd_name) if isinstance(cmd, (PulpCommand, PulpGroup)): @@ -223,7 +227,7 @@ def get_command(self, ctx: click.Context, cmd_name: str) -> Optional[click.Comma ) return cmd - def list_commands(self, ctx: click.Context) -> List[str]: + def list_commands(self, ctx: click.Context) -> t.List[str]: commands_filtered_by_context = [] for name, cmd in self.commands.items(): @@ -236,27 +240,31 @@ def list_commands(self, ctx: click.Context) -> List[str]: return sorted(commands_filtered_by_context) -def pulp_command(name: Optional[str] = None, **kwargs: Any) -> Callable[[F], click.Command]: +def pulp_command( + name: t.Optional[str] = None, **kwargs: t.Any +) -> t.Callable[[_AnyCallable], PulpCommand]: return click.command(name=name, cls=PulpCommand, **kwargs) -def pulp_group(name: Optional[str] = None, **kwargs: Any) -> Callable[[F], click.Group]: +def pulp_group( + name: t.Optional[str] = None, **kwargs: t.Any +) -> t.Callable[[_AnyCallable], PulpGroup]: return click.group(name=name, cls=PulpGroup, **kwargs) class PulpOption(click.Option): def __init__( self, - *args: Any, - needs_plugins: Optional[List[PluginRequirement]] = None, - allowed_with_contexts: Optional[Tuple[Type[PulpEntityContext]]] = None, - **kwargs: Any, + *args: t.Any, + needs_plugins: t.Optional[t.List[PluginRequirement]] = None, + allowed_with_contexts: t.Optional[t.Tuple[t.Type[PulpEntityContext]]] = None, + **kwargs: t.Any, ): self.needs_plugins = needs_plugins self.allowed_with_contexts = allowed_with_contexts super().__init__(*args, **kwargs) - def process_value(self, ctx: click.Context, value: Any) -> Any: + def process_value(self, ctx: click.Context, value: t.Any) -> t.Any: if self.needs_plugins and value is not None and value != (): pulp_ctx = ctx.find_object(PulpCLIContext) assert pulp_ctx is not None @@ -272,7 +280,7 @@ def process_value(self, ctx: click.Context, value: Any) -> Any: pulp_ctx.needs_plugin(plugin_requirement) return super().process_value(ctx, value) - def get_help_record(self, ctx: click.Context) -> Optional[Tuple[str, str]]: + def get_help_record(self, ctx: click.Context) -> t.Optional[t.Tuple[str, str]]: tmp = super().get_help_record(ctx) if tmp is None: return None @@ -284,8 +292,8 @@ def get_help_record(self, ctx: click.Context) -> Optional[Tuple[str, str]]: class GroupOption(PulpOption): - def __init__(self, *args: Any, **kwargs: Any) -> None: - self.group: List[str] = kwargs.pop("group") + def __init__(self, *args: t.Any, **kwargs: t.Any) -> None: + self.group: t.List[str] = kwargs.pop("group") assert self.group, "'group' parameter required" kwargs["help"] = ( kwargs.get("help", "") @@ -295,8 +303,8 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) def handle_parse_result( - self, ctx: click.Context, opts: Mapping[str, Any], args: List[Any] - ) -> Any: + self, ctx: click.Context, opts: t.Mapping[str, t.Any], args: t.List[t.Any] + ) -> t.Any: assert self.name is not None all_options = self.group + [self.name] options_present = [x for x in all_options if x in opts] @@ -322,11 +330,11 @@ def handle_parse_result( @lru_cache(typed=True) def lookup_callback( - attribute: str, context_class: Type[PulpEntityContext] = PulpEntityContext -) -> Callable[[click.Context, click.Parameter, Optional[str]], Optional[str]]: + attribute: str, context_class: t.Type[PulpEntityContext] = PulpEntityContext +) -> t.Callable[[click.Context, click.Parameter, t.Optional[str]], t.Optional[str]]: def _callback( - ctx: click.Context, param: click.Parameter, value: Optional[str] - ) -> Optional[str]: + ctx: click.Context, param: click.Parameter, value: t.Optional[str] + ) -> t.Optional[str]: if value is not None: if value == "": value = "null" @@ -339,11 +347,11 @@ def _callback( def href_callback( - context_class: Type[PulpEntityContext] = PulpEntityContext, -) -> Callable[[click.Context, click.Parameter, Optional[str]], Optional[str]]: + context_class: t.Type[PulpEntityContext] = PulpEntityContext, +) -> t.Callable[[click.Context, click.Parameter, t.Optional[str]], t.Optional[str]]: def _href_callback( - ctx: click.Context, param: click.Parameter, value: Optional[str] - ) -> Optional[str]: + ctx: click.Context, param: click.Parameter, value: t.Optional[str] + ) -> t.Optional[str]: if value is not None: entity_ctx = ctx.find_object(context_class) assert entity_ctx is not None @@ -354,8 +362,8 @@ def _href_callback( def _version_callback( - ctx: click.Context, param: click.Parameter, value: Optional[int] -) -> Optional[int]: + ctx: click.Context, param: click.Parameter, value: t.Optional[int] +) -> t.Optional[int]: entity_ctx = ctx.find_object(PulpEntityContext) assert entity_ctx is not None repository_ctx = ctx.find_object(PulpRepositoryContext) @@ -367,13 +375,13 @@ def _version_callback( return value -def load_file_wrapper(handler: Callable[[click.Context, click.Parameter, str], Any]) -> Any: +def load_file_wrapper(handler: t.Callable[[click.Context, click.Parameter, str], t.Any]) -> t.Any: """A wrapper that used for chaining or decorating callbacks that manipulate with input data.""" @wraps(handler) def _load_file_or_string_wrapper( - ctx: click.Context, param: click.Parameter, value: Optional[str] - ) -> Any: + ctx: click.Context, param: click.Parameter, value: t.Optional[str] + ) -> t.Any: """Load the string from input, or from file if the value starts with @.""" if not value: return value @@ -398,7 +406,7 @@ def _load_file_or_string_wrapper( load_string_callback = load_file_wrapper(lambda c, p, x: x) -def json_callback(ctx: click.Context, param: click.Parameter, value: Optional[str]) -> Any: +def json_callback(ctx: click.Context, param: click.Parameter, value: t.Optional[str]) -> t.Any: if value is None: return None @@ -414,8 +422,8 @@ def json_callback(ctx: click.Context, param: click.Parameter, value: Optional[st def load_labels_callback( - ctx: click.Context, param: click.Parameter, value: Optional[str] -) -> Optional[Dict[str, str]]: + ctx: click.Context, param: click.Parameter, value: t.Optional[str] +) -> t.Optional[t.Dict[str, str]]: if value is None: return value @@ -428,12 +436,12 @@ def load_labels_callback( def create_content_json_callback( - context_class: Optional[Type[PulpContentContext]] = None, schema: s.Schema = None -) -> Any: + context_class: t.Optional[t.Type[PulpContentContext]] = None, schema: s.Schema = None +) -> t.Any: @load_file_wrapper def _callback( ctx: click.Context, param: click.Parameter, value: str - ) -> Optional[List[PulpContentContext]]: + ) -> t.Optional[t.List[PulpContentContext]]: ctx_class = context_class new_value = json_callback(ctx, param, value) if new_value is not None: @@ -472,8 +480,8 @@ def parse_size_callback(ctx: click.Context, param: click.Parameter, value: str) def null_callback( - ctx: click.Context, param: click.Parameter, value: Optional[str] -) -> Optional[str]: + ctx: click.Context, param: click.Parameter, value: t.Optional[str] +) -> t.Optional[str]: if value == "": return "null" return value @@ -483,7 +491,7 @@ def null_callback( # Decorator common options -def pulp_option(*args: Any, **kwargs: Any) -> Callable[[FC], FC]: +def pulp_option(*args: t.Any, **kwargs: t.Any) -> t.Callable[[FC], FC]: kwargs["cls"] = PulpOption return click.option(*args, **kwargs) @@ -491,12 +499,12 @@ def pulp_option(*args: Any, **kwargs: Any) -> Callable[[FC], FC]: domain_pattern = r"(?P[-a-zA-Z0-9_]+)" -def resource_lookup_option(*args: Any, **kwargs: Any) -> Callable[[FC], FC]: +def resource_lookup_option(*args: t.Any, **kwargs: t.Any) -> t.Callable[[FC], FC]: lookup_key: str = kwargs.pop("lookup_key", "name") - context_class: Type[PulpEntityContext] = kwargs.pop("context_class") + context_class: t.Type[PulpEntityContext] = kwargs.pop("context_class") def _option_callback( - ctx: click.Context, param: click.Parameter, value: Optional[str] + ctx: click.Context, param: click.Parameter, value: t.Optional[str] ) -> EntityFieldDefinition: # Pass None and "" verbatim if not value: @@ -542,26 +550,26 @@ def _option_callback( return click.option(*args, **kwargs) -def resource_option(*args: Any, **kwargs: Any) -> Callable[[FC], FC]: - default_plugin: Optional[str] = kwargs.pop("default_plugin", None) - default_type: Optional[str] = kwargs.pop("default_type", None) +def resource_option(*args: t.Any, **kwargs: t.Any) -> t.Callable[[FC], FC]: + default_plugin: t.Optional[str] = kwargs.pop("default_plugin", None) + default_type: t.Optional[str] = kwargs.pop("default_type", None) lookup_key: str = kwargs.pop("lookup_key", "name") - context_table: Dict[str, Type[PulpEntityContext]] = kwargs.pop("context_table") - capabilities: Optional[List[str]] = kwargs.pop("capabilities", None) - href_pattern: Optional[str] = kwargs.pop("href_pattern", None) - parent_resource_lookup: Optional[Tuple[str, Type[PulpEntityContext]]] = kwargs.pop( + context_table: t.Dict[str, t.Type[PulpEntityContext]] = kwargs.pop("context_table") + capabilities: t.Optional[t.List[str]] = kwargs.pop("capabilities", None) + href_pattern: t.Optional[str] = kwargs.pop("href_pattern", None) + parent_resource_lookup: t.Optional[t.Tuple[str, t.Type[PulpEntityContext]]] = kwargs.pop( "parent_resource_lookup", None ) def _option_callback( - ctx: click.Context, param: click.Parameter, value: Optional[str] + ctx: click.Context, param: click.Parameter, value: t.Optional[str] ) -> EntityFieldDefinition: # Pass None and "" verbatim if not value: return value - pulp_href: Optional[str] = None - entity: Optional[EntityDefinition] = None + pulp_href: t.Optional[str] = None + entity: t.Optional[EntityDefinition] = None pulp_ctx = ctx.find_object(PulpCLIContext) assert pulp_ctx is not None @@ -643,8 +651,8 @@ def _option_callback( return entity_ctx def _multi_option_callback( - ctx: click.Context, param: click.Parameter, value: Iterable[Optional[str]] - ) -> Iterable[EntityFieldDefinition]: + ctx: click.Context, param: click.Parameter, value: t.Iterable[t.Optional[str]] + ) -> t.Iterable[EntityFieldDefinition]: if value: return (_option_callback(ctx, param, item) for item in value) return tuple() @@ -674,8 +682,8 @@ def _multi_option_callback( return click.option(*args, **kwargs) -def type_option(*args: Any, **kwargs: Any) -> Callable[[FC], FC]: - choices: Dict[str, Type[PulpEntityContext]] = kwargs.pop("choices") +def type_option(*args: t.Any, **kwargs: t.Any) -> t.Callable[[FC], FC]: + choices: t.Dict[str, t.Type[PulpEntityContext]] = kwargs.pop("choices") assert choices and isinstance(choices, dict) type_names = list(choices.keys()) case_sensitive = kwargs.pop("case_sensitive", False) @@ -686,7 +694,7 @@ def type_option(*args: Any, **kwargs: Any) -> Callable[[FC], FC]: "expose_value": False, } - def _type_callback(ctx: click.Context, param: click.Parameter, value: Optional[str]) -> str: + def _type_callback(ctx: click.Context, param: click.Parameter, value: t.Optional[str]) -> str: pulp_ctx = ctx.find_object(PulpCLIContext) assert pulp_ctx if value is not None: @@ -1051,14 +1059,16 @@ def _type_callback(ctx: click.Context, param: click.Parameter, value: Optional[s # Generic reusable commands -def list_command(**kwargs: Any) -> click.Command: +def list_command(**kwargs: t.Any) -> click.Command: """A factory that creates a list command.""" kwargs.setdefault("name", "list") kwargs.setdefault("help", _("Show the list of optionally filtered {entities}.")) decorators = kwargs.pop("decorators", []) - @pulp_command(**kwargs) + # This is a mypy bug getting confused with positional args + # https://github.com/python/mypy/issues/15037 + @pulp_command(**kwargs) # type: ignore [arg-type] @limit_option @offset_option @ordering_option @@ -1071,7 +1081,7 @@ def callback( entity_ctx: PulpEntityContext, limit: int, offset: int, - **kwargs: Any, + **kwargs: t.Any, ) -> None: """ Show the list of optionally filtered {entities}. @@ -1089,7 +1099,7 @@ def callback( return callback -def show_command(**kwargs: Any) -> click.Command: +def show_command(**kwargs: t.Any) -> click.Command: """A factory that creates a show command.""" if "name" not in kwargs: @@ -1113,7 +1123,7 @@ def callback(pulp_ctx: PulpCLIContext, entity_ctx: PulpEntityContext) -> None: return callback -def create_command(**kwargs: Any) -> click.Command: +def create_command(**kwargs: t.Any) -> click.Command: """A factory that creates a create command.""" if "name" not in kwargs: @@ -1122,10 +1132,12 @@ def create_command(**kwargs: Any) -> click.Command: kwargs["help"] = _("Create a {entity}.") decorators = kwargs.pop("decorators", []) - @pulp_command(**kwargs) + # This is a mypy bug getting confused with positional args + # https://github.com/python/mypy/issues/15037 + @pulp_command(**kwargs) # type: ignore [arg-type] @pass_entity_context @pass_pulp_context - def callback(pulp_ctx: PulpCLIContext, entity_ctx: PulpEntityContext, **kwargs: Any) -> None: + def callback(pulp_ctx: PulpCLIContext, entity_ctx: PulpEntityContext, **kwargs: t.Any) -> None: """ Create a {entity}. """ @@ -1141,7 +1153,7 @@ def callback(pulp_ctx: PulpCLIContext, entity_ctx: PulpEntityContext, **kwargs: return callback -def update_command(**kwargs: Any) -> click.Command: +def update_command(**kwargs: t.Any) -> click.Command: """A factory that creates an update command.""" if "name" not in kwargs: @@ -1150,10 +1162,12 @@ def update_command(**kwargs: Any) -> click.Command: kwargs["help"] = _("Update a {entity}.") decorators = kwargs.pop("decorators", []) - @pulp_command(**kwargs) + # This is a mypy bug getting confused with positional args + # https://github.com/python/mypy/issues/15037 + @pulp_command(**kwargs) # type: ignore [arg-type] @pass_entity_context @pass_pulp_context - def callback(pulp_ctx: PulpCLIContext, entity_ctx: PulpEntityContext, **kwargs: Any) -> None: + def callback(pulp_ctx: PulpCLIContext, entity_ctx: PulpEntityContext, **kwargs: t.Any) -> None: """ Update a {entity}. """ @@ -1165,7 +1179,7 @@ def callback(pulp_ctx: PulpCLIContext, entity_ctx: PulpEntityContext, **kwargs: return callback -def destroy_command(**kwargs: Any) -> click.Command: +def destroy_command(**kwargs: t.Any) -> click.Command: """A factory that creates a destroy command.""" kwargs.setdefault("name", "destroy") @@ -1186,7 +1200,7 @@ def callback(entity_ctx: PulpEntityContext) -> None: return callback -def version_command(**kwargs: Any) -> click.Command: +def version_command(**kwargs: t.Any) -> click.Command: """A factory that creates a repository version command group.""" kwargs.setdefault("name", "version") @@ -1223,7 +1237,7 @@ def repair( return callback -def label_command(**kwargs: Any) -> click.Command: +def label_command(**kwargs: t.Any) -> click.Command: """A factory that creates a label command group.""" kwargs.setdefault("name", "label") @@ -1266,7 +1280,7 @@ def label_show(entity_ctx: PulpEntityContext, key: str) -> None: return label_group -def role_command(**kwargs: Any) -> click.Command: +def role_command(**kwargs: t.Any) -> click.Command: """A factory that creates a (object) role command group.""" kwargs.setdefault("name", "role") @@ -1301,8 +1315,8 @@ def role_add( pulp_ctx: PulpCLIContext, entity_ctx: PulpEntityContext, role: str, - users: List[str], - groups: List[str], + users: t.List[str], + groups: t.List[str], ) -> None: result = entity_ctx.add_role(role, users, groups) pulp_ctx.output_result(result) @@ -1317,8 +1331,8 @@ def role_remove( pulp_ctx: PulpCLIContext, entity_ctx: PulpEntityContext, role: str, - users: List[str], - groups: List[str], + users: t.List[str], + groups: t.List[str], ) -> None: result = entity_ctx.remove_role(role, users, groups) pulp_ctx.output_result(result) @@ -1331,13 +1345,13 @@ def role_remove( return role_group -def repository_content_command(**kwargs: Any) -> click.Group: +def repository_content_command(**kwargs: t.Any) -> click.Group: """A factory that creates a repository content command group.""" content_contexts = kwargs.pop("contexts", {}) def version_callback( - ctx: click.Context, param: click.Parameter, value: Optional[int] + ctx: click.Context, param: click.Parameter, value: t.Optional[int] ) -> PulpRepositoryVersionContext: repo_ctx = ctx.find_object(PulpRepositoryContext) assert repo_ctx is not None @@ -1349,7 +1363,9 @@ def version_callback( ) return repo_ver_ctx - @pulp_command("list") + # This is a mypy bug getting confused with positional args + # https://github.com/python/mypy/issues/15037 + @pulp_command("list") # type: ignore [arg-type] @click.option("--all-types", is_flag=True) @limit_option @offset_option @@ -1364,7 +1380,7 @@ def content_list( offset: int, limit: int, all_types: bool, - **params: Any, + **params: t.Any, ) -> None: parameters = {k: v for k, v in params.items() if v is not None} parameters.update({"repository_version": version.pulp_href}) @@ -1402,15 +1418,15 @@ def content_remove( @click.option("--base-version", type=int, callback=version_callback) def content_modify( base_version: PulpRepositoryVersionContext, - add_content: Optional[List[PulpContentContext]], - remove_content: Optional[List[PulpContentContext]], + add_content: t.Optional[t.List[PulpContentContext]], + remove_content: t.Optional[t.List[PulpContentContext]], ) -> None: repo_ctx = base_version.repository_ctx ac = [unit.pulp_href for unit in add_content] if add_content else None rc = [unit.pulp_href for unit in remove_content] if remove_content else None repo_ctx.modify(add_content=ac, remove_content=rc, base_version=base_version.pulp_href) - command_decorators: Dict[click.Command, Optional[List[Callable[[FC], FC]]]] = { + command_decorators: t.Dict[click.Command, t.Optional[t.List[t.Callable[[FC], FC]]]] = { content_list: kwargs.pop("list_decorators", []), content_add: kwargs.pop("add_decorators", None), content_remove: kwargs.pop("remove_decorators", None), diff --git a/pulpcore/cli/container/distribution.py b/pulpcore/cli/container/distribution.py index 57770b21a..78aaae6e0 100644 --- a/pulpcore/cli/container/distribution.py +++ b/pulpcore/cli/container/distribution.py @@ -101,7 +101,7 @@ def distribution(ctx: click.Context, pulp_ctx: PulpCLIContext, distribution_type @pulp_labels_option @pass_entity_context def update( - distribution_ctx: PulpContainerDistributionContext, + distribution_ctx: PulpEntityContext, base_path: Optional[str], repository: Optional[Union[str, PulpEntityContext]], content_guard: EntityFieldDefinition, @@ -109,6 +109,8 @@ def update( private: Optional[bool], pulp_labels: Optional[Dict[str, str]], ) -> None: + assert isinstance(distribution_ctx, PulpContainerDistributionContext) + distribution: EntityDefinition = distribution_ctx.entity body: EntityDefinition = {} diff --git a/pulpcore/cli/container/repository.py b/pulpcore/cli/container/repository.py index 439bf9d13..40068e44f 100644 --- a/pulpcore/cli/container/repository.py +++ b/pulpcore/cli/container/repository.py @@ -182,10 +182,12 @@ def sync( @click.option("--digest", help=_("SHA256 digest of the Manifest file"), required=True) @pass_repository_context def add_tag( - repository_ctx: PulpContainerBaseRepositoryContext, + repository_ctx: PulpRepositoryContext, digest: str, tag: str, ) -> None: + assert isinstance(repository_ctx, PulpContainerBaseRepositoryContext) + digest = digest.strip() if not digest.startswith("sha256:"): digest = f"sha256:{digest}" @@ -201,7 +203,9 @@ def add_tag( @repository_lookup_option @click.option("--tag", help=_("Name of tag to remove"), required=True, callback=_tag_callback) @pass_repository_context -def remove_tag(repository_ctx: PulpContainerBaseRepositoryContext, tag: str) -> None: +def remove_tag(repository_ctx: PulpRepositoryContext, tag: str) -> None: + assert isinstance(repository_ctx, PulpContainerBaseRepositoryContext) + repository_ctx.untag(tag) @@ -219,11 +223,13 @@ def remove_tag(repository_ctx: PulpContainerBaseRepositoryContext, tag: str) -> ) @pass_repository_context def copy_tag( - repository_ctx: PulpContainerRepositoryContext, + repository_ctx: PulpRepositoryContext, source: PulpRepositoryContext, version: Optional[int], tags: List[str], ) -> None: + assert isinstance(repository_ctx, PulpContainerRepositoryContext) + href = source.entity["latest_version_href"] if version is not None: latest_version = int(href.split("/")[-2]) @@ -267,12 +273,14 @@ def copy_tag( ) @pass_repository_context def copy_manifest( - repository_ctx: PulpContainerRepositoryContext, + repository_ctx: PulpRepositoryContext, source: PulpRepositoryContext, version: Optional[int], digests: List[str], media_types: List[str], ) -> None: + assert isinstance(repository_ctx, PulpContainerRepositoryContext) + href = source.entity["latest_version_href"] if version is not None: latest_version = int(href.split("/")[-2]) @@ -297,9 +305,11 @@ def copy_manifest( @click.option("--digest", help=_("SHA256 digest of the Manifest file"), required=True) @pass_repository_context def remove_image( - repository_ctx: PulpContainerPushRepositoryContext, + repository_ctx: PulpRepositoryContext, digest: str, ) -> None: + assert isinstance(repository_ctx, PulpContainerPushRepositoryContext) + digest = digest.strip() if not digest.startswith("sha256:"): digest = f"sha256:{digest}" diff --git a/pulpcore/cli/core/access_policy.py b/pulpcore/cli/core/access_policy.py index 852763211..a9b6ef9c5 100644 --- a/pulpcore/cli/core/access_policy.py +++ b/pulpcore/cli/core/access_policy.py @@ -1,4 +1,5 @@ import click +from pulp_glue.common.context import PulpEntityContext from pulp_glue.common.i18n import get_translation from pulp_glue.core.context import PulpAccessPolicyContext @@ -46,6 +47,8 @@ def access_policy(ctx: click.Context, pulp_ctx: PulpCLIContext) -> None: @click.option("--viewset-name", callback=lookup_callback("viewset_name"), expose_value=False) @pass_entity_context @pass_pulp_context -def reset(pulp_ctx: PulpCLIContext, access_policy_ctx: PulpAccessPolicyContext) -> None: +def reset(pulp_ctx: PulpCLIContext, access_policy_ctx: PulpEntityContext) -> None: + assert isinstance(access_policy_ctx, PulpAccessPolicyContext) + result = access_policy_ctx.reset() pulp_ctx.output_result(result) diff --git a/pulpcore/cli/core/artifact.py b/pulpcore/cli/core/artifact.py index 6ff4771f3..49c427ec0 100644 --- a/pulpcore/cli/core/artifact.py +++ b/pulpcore/cli/core/artifact.py @@ -1,6 +1,7 @@ from typing import IO import click +from pulp_glue.common.context import PulpEntityContext from pulp_glue.common.i18n import get_translation from pulp_glue.core.context import PulpArtifactContext @@ -66,9 +67,11 @@ def artifact(ctx: click.Context, pulp_ctx: PulpCLIContext) -> None: @pass_pulp_context def upload( pulp_ctx: PulpCLIContext, - artifact_ctx: PulpArtifactContext, + artifact_ctx: PulpEntityContext, file: IO[bytes], chunk_size: int, ) -> None: + assert isinstance(artifact_ctx, PulpArtifactContext) + artifact_ctx.upload(file, chunk_size) pulp_ctx.output_result(artifact_ctx.entity) diff --git a/pulpcore/cli/core/content_guard.py b/pulpcore/cli/core/content_guard.py index bb23954a8..cf1871d99 100644 --- a/pulpcore/cli/core/content_guard.py +++ b/pulpcore/cli/core/content_guard.py @@ -2,7 +2,7 @@ import click from pulp_glue.certguard.context import PulpRHSMCertGuardContext, PulpX509CertGuardContext -from pulp_glue.common.context import PulpContentGuardContext +from pulp_glue.common.context import PulpContentGuardContext, PulpEntityContext from pulp_glue.common.i18n import get_translation from pulp_glue.core.context import ( PulpContentRedirectContentGuardContext, @@ -77,10 +77,12 @@ def rbac(ctx: click.Context, pulp_ctx: PulpCLIContext) -> None: @pass_pulp_context def assign( pulp_ctx: PulpCLIContext, - guard_ctx: PulpRbacContentGuardContext, + guard_ctx: PulpEntityContext, users: Optional[List[str]], groups: Optional[List[str]], ) -> None: + assert isinstance(guard_ctx, PulpRbacContentGuardContext) + result = guard_ctx.assign(users=users, groups=groups) pulp_ctx.output_result(result) @@ -104,10 +106,12 @@ def assign( @pass_pulp_context def remove( pulp_ctx: PulpCLIContext, - guard_ctx: PulpRbacContentGuardContext, + guard_ctx: PulpEntityContext, users: Optional[List[str]], groups: Optional[List[str]], ) -> None: + assert isinstance(guard_ctx, PulpRbacContentGuardContext) + result = guard_ctx.remove(users=users, groups=groups) pulp_ctx.output_result(result) diff --git a/pulpcore/cli/core/export.py b/pulpcore/cli/core/export.py index e93357f8c..c147afecb 100644 --- a/pulpcore/cli/core/export.py +++ b/pulpcore/cli/core/export.py @@ -15,7 +15,6 @@ PulpCLIContext, destroy_command, href_option, - pass_entity_context, pass_pulp_context, pulp_group, show_command, @@ -24,6 +23,8 @@ translation = get_translation(__name__) _ = translation.gettext +pass_export_context = click.make_pass_decorator(PulpExportContext) + def _version_list_callback( ctx: click.Context, param: click.Parameter, value: Iterable[Tuple[str, int]] @@ -98,13 +99,15 @@ def pulp(ctx: click.Context, pulp_ctx: PulpCLIContext) -> None: pulp.add_command(destroy_command(decorators=lookup_options)) -@pulp.command() +# This is a mypy bug getting confused with positional args +# https://github.com/python/mypy/issues/15037 +@pulp.command() # type: ignore [arg-type] @click.option("--exporter", type=str, required=True, help=_("Name of owning PulpExporter")) @click.option( "--limit", default=DEFAULT_LIMIT, type=int, help=_("Limit the number of exporters to show.") ) @click.option("--offset", default=0, type=int, help=_("Skip a number of exporters to show.")) -@pass_entity_context +@pass_export_context @pass_pulp_context def list( pulp_ctx: PulpCLIContext, @@ -129,7 +132,7 @@ def list( @click.option( "--start-versions", type=tuple([str, int]), multiple=True, callback=_version_list_callback ) -@pass_entity_context +@pass_export_context @pass_pulp_context def run( pulp_ctx: PulpCLIContext, diff --git a/pulpcore/cli/core/exporter.py b/pulpcore/cli/core/exporter.py index 548d88223..38fb44ffb 100644 --- a/pulpcore/cli/core/exporter.py +++ b/pulpcore/cli/core/exporter.py @@ -1,7 +1,7 @@ from typing import Any, Dict, Iterable import click -from pulp_glue.common.context import EntityFieldDefinition, PulpEntityContext, PulpRepositoryContext +from pulp_glue.common.context import EntityFieldDefinition, PulpRepositoryContext from pulp_glue.common.i18n import get_translation from pulp_glue.core.context import PulpExporterContext @@ -11,7 +11,6 @@ href_option, list_command, name_option, - pass_entity_context, pass_pulp_context, pulp_group, resource_option, @@ -21,6 +20,8 @@ translation = get_translation(__name__) _ = translation.gettext +pass_exporter_context = click.make_pass_decorator(PulpExporterContext) + multi_repository_option = resource_option( "--repository", @@ -60,7 +61,7 @@ def pulp(ctx: click.Context, pulp_ctx: PulpCLIContext) -> None: @click.option("--path", required=True) @multi_repository_option @click.option("--repository-href", multiple=True) -@pass_entity_context +@pass_exporter_context @pass_pulp_context def create( pulp_ctx: PulpCLIContext, @@ -73,7 +74,7 @@ def create( repo_hrefs = [ repository_ctx.pulp_href for repository_ctx in repository - if isinstance(repository_ctx, PulpEntityContext) + if isinstance(repository_ctx, PulpRepositoryContext) ] + list(repository_href) params = {"name": name, "path": path, "repositories": repo_hrefs} @@ -87,7 +88,7 @@ def create( @click.option("--path") @multi_repository_option @click.option("--repository-href", multiple=True) # This should be deprecated -@pass_entity_context +@pass_exporter_context @pass_pulp_context def update( pulp_ctx: PulpCLIContext, @@ -105,7 +106,7 @@ def update( payload["repositories"] = [ repository_ctx.pulp_href for repository_ctx in repository - if isinstance(repository_ctx, PulpEntityContext) + if isinstance(repository_ctx, PulpRepositoryContext) ] + list(repository_href) exporter_ctx.update(body=payload) diff --git a/pulpcore/cli/core/group.py b/pulpcore/cli/core/group.py index fc356c322..cd42fc363 100644 --- a/pulpcore/cli/core/group.py +++ b/pulpcore/cli/core/group.py @@ -1,7 +1,7 @@ from typing import Optional import click -from pulp_glue.common.context import PluginRequirement +from pulp_glue.common.context import PluginRequirement, PulpEntityContext from pulp_glue.common.i18n import get_translation from pulp_glue.core.context import ( PulpDomainContext, @@ -34,6 +34,8 @@ translation = get_translation(__name__) _ = translation.gettext +pass_group_context = click.make_pass_decorator(PulpGroupContext) + def _object_callback(ctx: click.Context, param: click.Parameter, value: str) -> str: entity_ctx = ctx.find_object(PulpGroupPermissionContext) @@ -117,7 +119,7 @@ def group(ctx: click.Context, pulp_ctx: PulpCLIContext) -> None: type=click.Choice(["model", "object"], case_sensitive=False), default="model", ) -@pass_entity_context +@pass_group_context @pass_pulp_context @click.pass_context def permission( @@ -146,9 +148,9 @@ def permission( @click.option("--permission", required=True) @click.option("--object", "obj", callback=_object_callback) @pass_entity_context -def add_permission( - entity_ctx: PulpGroupPermissionContext, permission: str, obj: Optional[str] -) -> None: +def add_permission(entity_ctx: PulpEntityContext, permission: str, obj: Optional[str]) -> None: + assert isinstance(entity_ctx, PulpGroupPermissionContext) + body = {"permission": permission} if obj: body["obj"] = obj @@ -174,7 +176,7 @@ def add_permission( @group.group() -@pass_entity_context +@pass_group_context @pass_pulp_context @click.pass_context def user(ctx: click.Context, pulp_ctx: PulpCLIContext, group_ctx: PulpGroupContext) -> None: @@ -193,7 +195,9 @@ def user(ctx: click.Context, pulp_ctx: PulpCLIContext, group_ctx: PulpGroupConte @click.option("--username", required=True) @pass_entity_context @pass_pulp_context -def remove_user(pulp_ctx: PulpCLIContext, entity_ctx: PulpGroupUserContext, username: str) -> None: +def remove_user(pulp_ctx: PulpCLIContext, entity_ctx: PulpEntityContext, username: str) -> None: + assert isinstance(entity_ctx, PulpGroupUserContext) + user_href = PulpUserContext(pulp_ctx).find(username=username)["pulp_href"] user_pk = user_href.split("/")[-2] group_user_href = f"{entity_ctx.group_ctx.pulp_href}users/{user_pk}/" @@ -202,7 +206,7 @@ def remove_user(pulp_ctx: PulpCLIContext, entity_ctx: PulpGroupUserContext, user @group.group(name="role-assignment") -@pass_entity_context +@pass_group_context @pass_pulp_context @click.pass_context def role(ctx: click.Context, pulp_ctx: PulpCLIContext, group_ctx: PulpGroupContext) -> None: diff --git a/pulpcore/cli/core/importer.py b/pulpcore/cli/core/importer.py index c89932029..988a81c72 100644 --- a/pulpcore/cli/core/importer.py +++ b/pulpcore/cli/core/importer.py @@ -10,7 +10,6 @@ href_option, list_command, name_option, - pass_entity_context, pass_pulp_context, pulp_group, show_command, @@ -19,6 +18,9 @@ translation = get_translation(__name__) _ = translation.gettext +pass_importer_context = click.make_pass_decorator(PulpImporterContext) + + RepositoryMap = Tuple[str, str] # source repo, destination repo repo_map_option = click.option( @@ -54,7 +56,7 @@ def pulp(ctx: click.Context, pulp_ctx: PulpCLIContext) -> None: @pulp.command() @click.option("--name", required=True) @repo_map_option -@pass_entity_context +@pass_importer_context @pass_pulp_context def create( pulp_ctx: PulpCLIContext, @@ -75,7 +77,7 @@ def create( @name_option @href_option @repo_map_option -@pass_entity_context +@pass_importer_context @pass_pulp_context def update( pulp_ctx: PulpCLIContext, diff --git a/pulpcore/cli/core/orphan.py b/pulpcore/cli/core/orphan.py index 28498c01d..98c2a00bb 100644 --- a/pulpcore/cli/core/orphan.py +++ b/pulpcore/cli/core/orphan.py @@ -1,7 +1,7 @@ from typing import Any import click -from pulp_glue.common.context import PluginRequirement +from pulp_glue.common.context import PluginRequirement, PulpEntityContext from pulp_glue.common.i18n import get_translation from pulp_glue.core.context import PulpOrphanContext @@ -28,7 +28,9 @@ def orphan(ctx: click.Context, pulp_ctx: PulpCLIContext) -> None: ctx.obj = PulpOrphanContext(pulp_ctx) -@orphan.command() +# This is a mypy bug getting confused with positional args +# https://github.com/python/mypy/issues/15037 +@orphan.command() # type: ignore [arg-type] @pulp_option( "--content-hrefs", help=_("List of specific Contents to delete if they are orphans"), @@ -47,8 +49,10 @@ def orphan(ctx: click.Context, pulp_ctx: PulpCLIContext) -> None: ) @pass_entity_context @pass_pulp_context -def cleanup(pulp_ctx: PulpCLIContext, orphan_ctx: PulpOrphanContext, **kwargs: Any) -> None: +def cleanup(pulp_ctx: PulpCLIContext, orphan_ctx: PulpEntityContext, **kwargs: Any) -> None: """ Cleanup orphaned content. """ + assert isinstance(orphan_ctx, PulpOrphanContext) + pulp_ctx.output_result(orphan_ctx.cleanup(kwargs)) diff --git a/pulpcore/cli/core/task.py b/pulpcore/cli/core/task.py index 131465981..59c7a530f 100644 --- a/pulpcore/cli/core/task.py +++ b/pulpcore/cli/core/task.py @@ -17,7 +17,6 @@ destroy_command, href_option, list_command, - pass_entity_context, pass_pulp_context, pulp_group, pulp_option, @@ -29,6 +28,9 @@ _ = translation.gettext +pass_task_context = click.make_pass_decorator(PulpTaskContext) + + def _uuid_callback( ctx: click.Context, param: click.Parameter, value: Optional[str] ) -> Optional[str]: @@ -113,7 +115,7 @@ def task(ctx: click.Context, pulp_ctx: PulpCLIContext) -> None: @href_option @uuid_option @click.option("-w", "--wait", is_flag=True, help=_("Wait for the task to finish")) -@pass_entity_context +@pass_task_context @pass_pulp_context def show(pulp_ctx: PulpCLIContext, task_ctx: PulpTaskContext, wait: bool) -> None: """Shows details of a task.""" @@ -134,7 +136,7 @@ def show(pulp_ctx: PulpCLIContext, task_ctx: PulpTaskContext, wait: bool) -> Non ) @click.option("--waiting", "waiting_tasks", is_flag=True, help=_("Cancel all 'waiting' tasks.")) @click.option("--running", "running_tasks", is_flag=True, help=_("Cancel all 'running' tasks.")) -@pass_entity_context +@pass_task_context @pass_pulp_context def cancel( pulp_ctx: PulpCLIContext, @@ -181,7 +183,7 @@ def cancel( type=click.Choice(["skipped", "completed", "failed", "canceled"]), multiple=True, ) -@pass_entity_context +@pass_task_context def purge( task_ctx: PulpTaskContext, finished: Optional[datetime], @@ -192,7 +194,7 @@ def purge( @task.command() -@pass_entity_context +@pass_task_context @pass_pulp_context def summary(pulp_ctx: PulpCLIContext, task_ctx: PulpTaskContext) -> None: """ diff --git a/pulpcore/cli/core/task_group.py b/pulpcore/cli/core/task_group.py index 36eac2313..91c7315e5 100644 --- a/pulpcore/cli/core/task_group.py +++ b/pulpcore/cli/core/task_group.py @@ -53,8 +53,10 @@ def _uuid_callback( @click.option("-w", "--wait", is_flag=True, help=_("Wait for the group-task to finish")) @pass_entity_context @pass_pulp_context -def show(pulp_ctx: PulpCLIContext, task_group_ctx: PulpTaskGroupContext, wait: bool) -> None: +def show(pulp_ctx: PulpCLIContext, task_group_ctx: PulpEntityContext, wait: bool) -> None: """Shows details of a group-task.""" + assert isinstance(task_group_ctx, PulpTaskGroupContext) + entity = task_group_ctx.entity if wait: if not entity["all_tasks_dispatched"]: diff --git a/pulpcore/cli/core/user.py b/pulpcore/cli/core/user.py index 1475d450c..d69ef46c5 100644 --- a/pulpcore/cli/core/user.py +++ b/pulpcore/cli/core/user.py @@ -1,7 +1,7 @@ from typing import Optional import click -from pulp_glue.common.context import PluginRequirement +from pulp_glue.common.context import PluginRequirement, PulpEntityContext from pulp_glue.common.i18n import get_translation from pulp_glue.core.context import PulpDomainContext, PulpUserContext, PulpUserRoleContext @@ -111,7 +111,9 @@ def user(ctx: click.Context, pulp_ctx: PulpCLIContext) -> None: @pass_entity_context @pass_pulp_context @click.pass_context -def role(ctx: click.Context, pulp_ctx: PulpCLIContext, user_ctx: PulpUserContext) -> None: +def role(ctx: click.Context, pulp_ctx: PulpCLIContext, user_ctx: PulpEntityContext) -> None: + assert isinstance(user_ctx, PulpUserContext) + pulp_ctx.needs_plugin(req_core_3_17) ctx.obj = PulpUserRoleContext(pulp_ctx, user_ctx) diff --git a/pulpcore/cli/file/acs.py b/pulpcore/cli/file/acs.py index 71bcd5156..56b9ab622 100644 --- a/pulpcore/cli/file/acs.py +++ b/pulpcore/cli/file/acs.py @@ -1,7 +1,7 @@ from typing import Iterable import click -from pulp_glue.common.context import PulpRemoteContext +from pulp_glue.common.context import PulpACSContext, PulpRemoteContext from pulp_glue.common.i18n import get_translation from pulp_glue.file.context import PulpFileACSContext, PulpFileRemoteContext @@ -13,7 +13,7 @@ href_option, list_command, name_option, - pass_entity_context, + pass_acs_context, pass_pulp_context, pulp_group, resource_option, @@ -59,8 +59,8 @@ def path() -> None: @href_option @acs_lookup_option @path_option -@pass_entity_context -def add(acs_ctx: PulpFileACSContext, paths: Iterable[str]) -> None: +@pass_acs_context +def add(acs_ctx: PulpACSContext, paths: Iterable[str]) -> None: """Add path(s) to an existing ACS.""" paths = set(paths) existing_paths = set(acs_ctx.entity["paths"]) @@ -79,8 +79,8 @@ def add(acs_ctx: PulpFileACSContext, paths: Iterable[str]) -> None: @href_option @acs_lookup_option @path_option -@pass_entity_context -def remove(acs_ctx: PulpFileACSContext, paths: Iterable[str]) -> None: +@pass_acs_context +def remove(acs_ctx: PulpACSContext, paths: Iterable[str]) -> None: """Remove path(s) from an existing ACS.""" paths = set(paths) existing_paths = set(acs_ctx.entity["paths"]) @@ -114,10 +114,10 @@ def remove(acs_ctx: PulpFileACSContext, paths: Iterable[str]) -> None: @acs.command() -@pass_entity_context -@pass_pulp_context +@acs_lookup_option @href_option @name_option -@acs_lookup_option -def refresh(pulp_ctx: PulpCLIContext, acs_ctx: PulpFileACSContext) -> None: +@pass_acs_context +@pass_pulp_context +def refresh(pulp_ctx: PulpCLIContext, acs_ctx: PulpACSContext) -> None: acs_ctx.refresh() diff --git a/pulpcore/cli/file/content.py b/pulpcore/cli/file/content.py index 26f35272e..1ba7d6b6d 100644 --- a/pulpcore/cli/file/content.py +++ b/pulpcore/cli/file/content.py @@ -120,13 +120,15 @@ def content(ctx: click.Context, pulp_ctx: PulpCLIContext, content_type: str) -> @pass_pulp_context def upload( pulp_ctx: PulpCLIContext, - entity_ctx: PulpFileContentContext, + entity_ctx: PulpEntityContext, relative_path: str, file: IO[bytes], chunk_size: int, repository: Optional[PulpRepositoryContext], ) -> None: """Create a file content unit by uploading a file""" + assert isinstance(entity_ctx, PulpFileContentContext) + result = entity_ctx.upload( relative_path=relative_path, file=file, chunk_size=chunk_size, repository=repository ) diff --git a/pulpcore/cli/migration/plan.py b/pulpcore/cli/migration/plan.py index 223c831a2..1bd9f6346 100644 --- a/pulpcore/cli/migration/plan.py +++ b/pulpcore/cli/migration/plan.py @@ -8,7 +8,6 @@ href_option, list_command, load_json_callback, - pass_entity_context, pass_pulp_context, pulp_group, show_command, @@ -18,6 +17,8 @@ translation = get_translation(__name__) _ = translation.gettext +pass_migration_plan_context = click.make_pass_decorator(PulpMigrationPlanContext) + @pulp_group() @pass_pulp_context @@ -46,13 +47,13 @@ def plan(ctx: click.Context, pulp_ctx: PulpCLIContext) -> None: @plan.command(help=_("Run migration plan")) @click.option("--href", required=True, help=_("HREF of the plan")) -@pass_entity_context +@pass_migration_plan_context def run(plan_ctx: PulpMigrationPlanContext, href: str) -> None: plan_ctx.run(href) @plan.command(help=_("Reset Pulp 3 data for plugins specified in the migration plan")) @click.option("--href", required=True, help=_("HREF of the plan")) -@pass_entity_context +@pass_migration_plan_context def reset(plan_ctx: PulpMigrationPlanContext, href: str) -> None: plan_ctx.reset(href) diff --git a/pulpcore/cli/python/content.py b/pulpcore/cli/python/content.py index b6b128328..cb0d45384 100644 --- a/pulpcore/cli/python/content.py +++ b/pulpcore/cli/python/content.py @@ -96,13 +96,15 @@ def content(ctx: click.Context, pulp_ctx: PulpCLIContext, content_type: str) -> @pass_pulp_context def upload( pulp_ctx: PulpCLIContext, - entity_ctx: PulpPythonContentContext, + entity_ctx: PulpEntityContext, relative_path: str, file: IO[bytes], chunk_size: int, repository: Optional[PulpPythonRepositoryContext], ) -> None: """Create a Python package content unit through uploading a file""" + assert isinstance(entity_ctx, PulpPythonContentContext) + result = entity_ctx.upload( relative_path=relative_path, file=file, chunk_size=chunk_size, repository=repository ) diff --git a/pulpcore/cli/rpm/acs.py b/pulpcore/cli/rpm/acs.py index 07dabc56f..317185628 100644 --- a/pulpcore/cli/rpm/acs.py +++ b/pulpcore/cli/rpm/acs.py @@ -1,7 +1,7 @@ from typing import Iterable import click -from pulp_glue.common.context import PulpRemoteContext +from pulp_glue.common.context import PulpACSContext, PulpRemoteContext from pulp_glue.common.i18n import get_translation from pulp_glue.rpm.context import PulpRpmACSContext, PulpRpmRemoteContext, PulpUlnRemoteContext @@ -13,7 +13,7 @@ href_option, list_command, name_option, - pass_entity_context, + pass_acs_context, pass_pulp_context, pulp_group, resource_option, @@ -59,8 +59,8 @@ def path() -> None: @href_option @acs_lookup_option @path_option -@pass_entity_context -def add(acs_ctx: PulpRpmACSContext, paths: Iterable[str]) -> None: +@pass_acs_context +def add(acs_ctx: PulpACSContext, paths: Iterable[str]) -> None: """Add path(s) to an existing ACS.""" paths = set(paths) existing_paths = set(acs_ctx.entity["paths"]) @@ -79,8 +79,8 @@ def add(acs_ctx: PulpRpmACSContext, paths: Iterable[str]) -> None: @href_option @acs_lookup_option @path_option -@pass_entity_context -def remove(acs_ctx: PulpRpmACSContext, paths: Iterable[str]) -> None: +@pass_acs_context +def remove(acs_ctx: PulpACSContext, paths: Iterable[str]) -> None: """Remove path(s) from an existing ACS.""" paths = set(paths) existing_paths = set(acs_ctx.entity["paths"]) @@ -114,10 +114,10 @@ def remove(acs_ctx: PulpRpmACSContext, paths: Iterable[str]) -> None: @acs.command() -@pass_entity_context -@pass_pulp_context -@href_option @acs_lookup_option +@href_option @name_option -def refresh(pulp_ctx: PulpCLIContext, acs_ctx: PulpRpmACSContext) -> None: +@pass_acs_context +@pass_pulp_context +def refresh(pulp_ctx: PulpCLIContext, acs_ctx: PulpACSContext) -> None: acs_ctx.refresh() diff --git a/pulpcore/cli/rpm/content.py b/pulpcore/cli/rpm/content.py index 447b97ec6..758ef061c 100644 --- a/pulpcore/cli/rpm/content.py +++ b/pulpcore/cli/rpm/content.py @@ -247,7 +247,9 @@ def content() -> None: # upload takes a file-argument and creates the entity from it. # upload currently only works for advisory/package, # see https://github.com/pulp/pulp_rpm/issues/2534 -@content.command( +# This is a mypy bug getting confused with positional args +# https://github.com/python/mypy/issues/15037 +@content.command( # type: ignore [arg-type] allowed_with_contexts=( PulpRpmPackageContext, PulpRpmAdvisoryContext, @@ -278,10 +280,7 @@ def content() -> None: @pass_pulp_context def upload( pulp_ctx: PulpCLIContext, - entity_ctx: Union[ - PulpRpmPackageContext, - PulpRpmAdvisoryContext, - ], + entity_ctx: PulpEntityContext, file: IO[bytes], chunk_size: int, **kwargs: Any, diff --git a/setup.py b/setup.py index ed59443ac..82b70d796 100644 --- a/setup.py +++ b/setup.py @@ -38,7 +38,7 @@ python_requires=">=3.6", install_requires=[ "pulp-glue==0.21.0.dev", - "click>=8.0.0,<8.1.4", + "click>=8.0.0,<8.1.7", "PyYAML>=5.3,<6.1", "schema>=0.7.5,<0.8", "toml>=0.10.2,<0.11",