return self._data._ipython_key_completions_()  def drop_coords(    coords_to_drop: set[Hashable], variables, indexes: Indexes) -> tuple[dict, dict]:    """Drop index variables associated with variables in coords_to_drop."""    # Only warn when we're dropping the dimension with the multi-indexed coordinate    # If asked to drop a subset of the levels in a multi-index, we raise an error    # later but skip the warning here.    new_variables = dict(variables.copy())    new_indexes = dict(indexes.copy())    for key in coords_to_drop & set(indexes):        maybe_midx = indexes[key]        idx_coord_names = set(indexes.get_all_coords(key))        if (            isinstance(maybe_midx, PandasMultiIndex)            and key == maybe_midx.dim            and (idx_coord_names - coords_to_drop)        ):            warnings.warn(                f"Updating MultiIndexed coordinate {key!r} would corrupt indices for "                f"other variables: {list(maybe_midx.index.names)!r}. "                f"This will raise an error in the future. Use `.drop_vars({idx_coord_names!r})` before "                "assigning new coordinate values.",                DeprecationWarning,                stacklevel=4,            )            for k in idx_coord_names:                del new_variables[k]                del new_indexes[k]    return new_variables, new_indexes def assert_coordinate_consistent(     obj: DataArray | Dataset, coords: Mapping[Any, Variable] ) -> None:diff --git a/xarray/core/dataset.py b/xarray/core/dataset.py-- a/xarray/core/dataset.py++ b/xarray/core/dataset.py


data = self.copy()         # do all calculations first...         results: CoercibleMapping = data._calc_assign_results(variables)        data.coords._maybe_drop_multiindex_coords(set(results.keys()))         # ... and then assign         data.update(results)         return datadiff --git a/xarray/core/indexes.py b/xarray/core/indexes.py-- a/xarray/core/indexes.py++ b/xarray/core/indexes.py


return Frozen(self._dims) <ins>    def copy(self):        return type(self)(dict(self._indexes), dict(self._variables))</ins>     def get_unique(self) -> list[T_PandasOrXarrayIndex]:         """Return a list of unique indexes, preserving order."""


if name in ["sum", "prod"]:                 kwargs.pop("min_count", None)             func = getattr(np, name)            if hasattr(values, "__array_namespace__"):                xp = values.__array_namespace__()                func = getattr(xp, name)            else:                func = getattr(np, name)          try:             with warnings.catch_warnings():diff --git a/xarray/core/indexing.py b/xarray/core/indexing.py-- a/xarray/core/indexing.py++ b/xarray/core/indexing.py


return DaskIndexingAdapter(array)     if hasattr(array, "__array_function__"):         return NdArrayLikeIndexingAdapter(array)<ins>    if hasattr(array, "__array_namespace__"):        return ArrayApiIndexingAdapter(array)</ins>      raise TypeError(f"Invalid array type: {type(array)}")


self.array = array  class ArrayApiIndexingAdapter(ExplicitlyIndexedNDArrayMixin):    """Wrap an array API array to use explicit indexing."""    __slots__ = ("array",)    def __init__(self, array):        if not hasattr(array, "__array_namespace__"):            raise TypeError(                "ArrayApiIndexingAdapter must wrap an object that "                "implements the __array_namespace__ protocol"            )        self.array = array    def __getitem__(self, key):        if isinstance(key, BasicIndexer):            return self.array[key.tuple]        elif isinstance(key, OuterIndexer):            # manual orthogonal indexing (implemented like DaskIndexingAdapter)            key = key.tuple            value = self.array            for axis, subkey in reversed(list(enumerate(key))):                value = value[(slice(None),) * axis + (subkey, Ellipsis)]            return value        else:            if isinstance(key, VectorizedIndexer):                raise TypeError("Vectorized indexing is not supported")            else:                raise TypeError(f"Unrecognized indexer: {key}")    def __setitem__(self, key, value):        if isinstance(key, (BasicIndexer, OuterIndexer)):            self.array[key.tuple] = value        else:            if isinstance(key, VectorizedIndexer):                raise TypeError("Vectorized indexing is not supported")            else:                raise TypeError(f"Unrecognized indexer: {key}")    def transpose(self, order):        xp = self.array.__array_namespace__()        return xp.permute_dims(self.array, order) class DaskIndexingAdapter(ExplicitlyIndexedNDArrayMixin):     """Wrap a dask array to support explicit indexing.""" diff --git a/xarray/core/utils.py b/xarray/core/utils.py-- a/xarray/core/utils.py++ b/xarray/core/utils.py


hasattr(value, "ndim")         and hasattr(value, "shape")         and hasattr(value, "dtype")        and hasattr(value, "__array_function__")        and hasattr(value, "__array_ufunc__")        and (            (hasattr(value, "__array_function__") and hasattr(value, "__array_ufunc__"))            or hasattr(value, "__array_namespace__")        )     )


or not (             isinstance(value, (Iterable,) + NON_NUMPY_SUPPORTED_ARRAY_TYPES)             or hasattr(value, "__array_function__")            or hasattr(value, "__array_namespace__")         )     ) diff --git a/xarray/core/variable.py b/xarray/core/variable.py-- a/xarray/core/variable.py++ b/xarray/core/variable.py


else:             data = np.asarray(data)     if not isinstance(data, np.ndarray) and hasattr(data, "__array_function__"):    if not isinstance(data, np.ndarray) and (        hasattr(data, "__array_function__") or hasattr(data, "__array_namespace__")    ):         return data      # validate whether the data is valid data types.


return f"
{escape(repr(self))}
"         return formatting_html.array_repr(self)     def __format__(self: Any, format_spec: str) -> str:        # we use numpy: scalars will print fine and arrays will raise        return self.values.__format__(format_spec)    def __format__(self: Any, format_spec: str = "") -> str:        if format_spec != "":            if self.shape == ():                # Scalar values might be ok use format_spec with instead of repr:                return self.data.__format__(format_spec)            else:                # TODO: If it's an array the formatting.array_repr(self) should                # take format_spec as an input. If we'd only use self.data we                # lose all the information about coords for example which is                # important information:                raise NotImplementedError(                    "Using format_spec is only supported"                    f" when shape is (). Got shape = {self.shape}."                )        else:            return self.__repr__()      def _iter(self: Any) -> Iterator[Any]:         for n in range(len(self)):


if obj_idx is not None:                     for name, var in self.aligned_index_vars[key].items():                         new_indexes[name] = aligned_idx                        new_variables[name] = var                        new_variables[name] = var.copy()              objects[i + 1] = obj._overwrite_indexes(new_indexes, new_variables)


if obj_idx is not None:                 for name, var in index_vars.items():                     new_indexes[name] = aligned_idx                    new_variables[name] = var                    new_variables[name] = var.copy()          return new_indexes, new_variables


def _decode_datetime_with_cftime(num_dates, units, calendar):     if cftime is None:         raise ModuleNotFoundError("No module named 'cftime'")    return np.asarray(        cftime.num2date(num_dates, units, calendar, only_use_cftime_datetimes=True)    )    if num_dates.size > 0:        return np.asarray(            cftime.num2date(num_dates, units, calendar, only_use_cftime_datetimes=True)        )    else:        return np.array([], dtype=object)   def _decode_datetime_with_pandas(flat_num_dates, units, calendar):


with warnings.catch_warnings():         warnings.filterwarnings("ignore", "invalid value encountered", RuntimeWarning)        pd.to_timedelta(flat_num_dates.min(), delta) + ref_date        pd.to_timedelta(flat_num_dates.max(), delta) + ref_date        if flat_num_dates.size > 0:            # avoid size 0 datetimes GH1329            pd.to_timedelta(flat_num_dates.min(), delta) + ref_date            pd.to_timedelta(flat_num_dates.max(), delta) + ref_date      # To avoid integer overflow when converting to nanosecond units for integer     # dtypes smaller than np.int64 cast all integer and unsigned integer dtype


)      # determine which variables to merge, and then merge them according to compat    variables_to_merge = (coord_names | data_names) - concat_over - dim_names    variables_to_merge = (coord_names | data_names) - concat_over - unlabeled_dims      result_vars = {}     result_indexes = {}


indexes: dict[Hashable, Index] = {}         for k, v in self.variables.items():             dims = tuple(dims_dict.get(dim, dim) for dim in v.dims)            var: Variable             if k in result_dims:                 var = v.to_index_variable()                 var.dims = dimsdiff --git a/xarray/core/variable.py b/xarray/core/variable.py-- a/xarray/core/variable.py++ b/xarray/core/variable.py


Iterable,     Literal,     Mapping,<ins>    NoReturn,</ins>     Sequence, )


def values(self, values):         self.data = values     def to_base_variable(self):    def to_base_variable(self) -> Variable:         """Return this variable as a base xarray.Variable"""         return Variable(            self.dims, self._data, self._attrs, encoding=self._encoding, fastpath=True            self._dims, self._data, self._attrs, encoding=self._encoding, fastpath=True         )      to_variable = utils.alias(to_base_variable, "to_variable")     def to_index_variable(self):    def to_index_variable(self) -> IndexVariable:         """Return this variable as an xarray.IndexVariable"""         return IndexVariable(            self.dims, self._data, self._attrs, encoding=self._encoding, fastpath=True            self._dims, self._data, self._attrs, encoding=self._encoding, fastpath=True         )      to_coord = utils.alias(to_index_variable, "to_coord")     def to_index(self):    def to_index(self) -> pd.Index:         """Convert this variable to a pandas.Index"""         return self.to_index_variable().to_index()


def _data_equals(self, other):         return self.to_index().equals(other.to_index())     def to_index_variable(self):    def to_index_variable(self) -> IndexVariable:         """Return this variable as an xarray.IndexVariable"""        return self        return self.copy()      to_coord = utils.alias(to_index_variable, "to_coord")     def to_index(self):    def to_index(self) -> pd.Index:         """Convert this variable to a pandas.Index"""         # n.b. creating a new pandas.Index from an old pandas.Index is         # basically free as pandas.Index objects are immutable


return index      @property    def level_names(self):    def level_names(self) -> list[str] | None:         """Return MultiIndex level names or None if this IndexVariable has no         MultiIndex.         """


return type(self)(self.dims, index.get_level_values(level))      @property    def name(self):    def name(self) -> Hashable:         return self.dims[0]      @name.setter    def name(self, value):    def name(self, value) -> NoReturn:         raise AttributeError("cannot modify name of IndexVariable in-place")      def _inplace_binary_op(self, other, f):


dim_coords = either_dict_or_kwargs(indexes, indexes_kwargs, "set_index")          new_indexes: dict[Hashable, Index] = {}        new_variables: dict[Hashable, IndexVariable] = {}        maybe_drop_indexes: list[Hashable] = []        drop_variables: list[Hashable] = []        new_variables: dict[Hashable, Variable] = {}        drop_indexes: set[Hashable] = set()        drop_variables: set[Hashable] = set()         replace_dims: dict[Hashable, Hashable] = {}        all_var_names: set[Hashable] = set()          for dim, _var_names in dim_coords.items():             if isinstance(_var_names, str) or not isinstance(_var_names, Sequence):


+ " variable(s) do not exist"                 )             current_coord_names = self.xindexes.get_all_coords(dim, errors="ignore")            all_var_names.update(var_names)            drop_variables.update(var_names)             # drop any pre-existing index involved            maybe_drop_indexes += list(current_coord_names) + var_names            # drop any pre-existing index involved and its corresponding coordinates            index_coord_names = self.xindexes.get_all_coords(dim, errors="ignore")            all_index_coord_names = set(index_coord_names)             for k in var_names:                maybe_drop_indexes += list(                all_index_coord_names.update(                     self.xindexes.get_all_coords(k, errors="ignore")                 )             drop_variables += var_names            drop_indexes.update(all_index_coord_names)            drop_variables.update(all_index_coord_names)              if len(var_names) == 1 and (not append or dim not in self._indexes):                 var_name = var_names[0]


)                 idx = PandasIndex.from_variables({dim: var})                 idx_vars = idx.create_variables({var_name: var})                # trick to preserve coordinate order in this case                if dim in self._coord_names:                    drop_variables.remove(dim)             else:                 if append:                     current_variables = {                        k: self._variables[k] for k in current_coord_names                        k: self._variables[k] for k in index_coord_names                     }                 else:                     current_variables = {}


new_indexes.update({k: idx for k in idx_vars})             new_variables.update(idx_vars)         # re-add deindexed coordinates (convert to base variables)        for k in drop_variables:            if (                k not in new_variables                and k not in all_var_names                and k in self._coord_names            ):                new_variables[k] = self._variables[k].to_base_variable()         indexes_: dict[Any, Index] = {            k: v for k, v in self._indexes.items() if k not in maybe_drop_indexes            k: v for k, v in self._indexes.items() if k not in drop_indexes         }         indexes_.update(new_indexes)


new_dims = [replace_dims.get(d, d) for d in v.dims]                 variables[k] = v._replace(dims=new_dims)         coord_names = self._coord_names - set(drop_variables) | set(new_variables)        coord_names = self._coord_names - drop_variables | set(new_variables)          return self._replace_with_new_dims(             variables, coord_names=coord_names, indexes=indexes_


f"{tuple(invalid_coords)} are not coordinates with an index"             )         drop_indexes: list[Hashable] = []        drop_variables: list[Hashable] = []        replaced_indexes: list[PandasMultiIndex] = []        drop_indexes: set[Hashable] = set()        drop_variables: set[Hashable] = set()        seen: set[Index] = set()         new_indexes: dict[Hashable, Index] = {}        new_variables: dict[Hashable, IndexVariable] = {}        new_variables: dict[Hashable, Variable] = {}        def drop_or_convert(var_names):            if drop:                drop_variables.update(var_names)            else:                base_vars = {                    k: self._variables[k].to_base_variable() for k in var_names                }                new_variables.update(base_vars)          for name in dims_or_levels:             index = self._indexes[name]            drop_indexes += list(self.xindexes.get_all_coords(name))            if isinstance(index, PandasMultiIndex) and name not in self.dims:                # special case for pd.MultiIndex (name is an index level):                # replace by a new index with dropped level(s) instead of just drop the index                if index not in replaced_indexes:                    level_names = index.index.names                    level_vars = {                        k: self._variables[k]                        for k in level_names                        if k not in dims_or_levels                    }                    if level_vars:                        idx = index.keep_levels(level_vars)                        idx_vars = idx.create_variables(level_vars)                        new_indexes.update({k: idx for k in idx_vars})                        new_variables.update(idx_vars)                replaced_indexes.append(index)             if drop:                drop_variables.append(name)            if index in seen:                continue            seen.add(index)            idx_var_names = set(self.xindexes.get_all_coords(name))            drop_indexes.update(idx_var_names)            if isinstance(index, PandasMultiIndex):                # special case for pd.MultiIndex                level_names = index.index.names                keep_level_vars = {                    k: self._variables[k]                    for k in level_names                    if k not in dims_or_levels                }                if index.dim not in dims_or_levels and keep_level_vars:                    # do not drop the multi-index completely                    # instead replace it by a new (multi-)index with dropped level(s)                    idx = index.keep_levels(keep_level_vars)                    idx_vars = idx.create_variables(keep_level_vars)                    new_indexes.update({k: idx for k in idx_vars})                    new_variables.update(idx_vars)                    if not isinstance(idx, PandasMultiIndex):                        # multi-index reduced to single index                        # backward compatibility: unique level coordinate renamed to dimension                        drop_variables.update(keep_level_vars)                    drop_or_convert(                        [k for k in level_names if k not in keep_level_vars]                    )                else:                    # always drop the multi-index dimension variable                    drop_variables.add(index.dim)                    drop_or_convert(level_names)            else:                drop_or_convert(idx_var_names)          indexes = {k: v for k, v in self._indexes.items() if k not in drop_indexes}         indexes.update(new_indexes)


}         variables.update(new_variables)         coord_names = set(new_variables) | self._coord_names        coord_names = self._coord_names - drop_variables         return self._replace(variables, coord_names=coord_names, indexes=indexes)        return self._replace_with_new_dims(            variables, coord_names=coord_names, indexes=indexes        )      def reorder_levels(         self: T_Dataset,diff --git a/xarray/core/indexes.py b/xarray/core/indexes.py-- a/xarray/core/indexes.py++ b/xarray/core/indexes.py


level_coords_dtype = {k: self.level_coords_dtype[k] for k in index.names}             return self._replace(index, level_coords_dtype=level_coords_dtype)         else:            # backward compatibility: rename the level coordinate to the dimension name             return PandasIndex(                index, self.dim, coord_dtype=self.level_coords_dtype[index.name]                index.rename(self.dim),                self.dim,                coord_dtype=self.level_coords_dtype[index.name],             )      def reorder_levels(


if utils.is_dict_like(new_name_or_name_dict) or new_name_or_name_dict is None:             # change dims/coords             name_dict = either_dict_or_kwargs(new_name_or_name_dict, names, "rename")            dataset = self._to_temp_dataset().rename(name_dict)            dataset = self._to_temp_dataset()._rename(name_dict)             return self._from_temp_dataset(dataset)         if utils.hashable(new_name_or_name_dict) and names:             # change name + dims/coords            dataset = self._to_temp_dataset().rename(names)            dataset = self._to_temp_dataset()._rename(names)             dataarray = self._from_temp_dataset(dataset)             return dataarray._replace(name=new_name_or_name_dict)         # only change namediff --git a/xarray/core/dataset.py b/xarray/core/dataset.py-- a/xarray/core/dataset.py++ b/xarray/core/dataset.py


return variables, coord_names, dims, indexes <ins>    def _rename(        self: T_Dataset,        name_dict: Mapping[Any, Hashable] | None = None,        **names: Hashable,    ) -> T_Dataset:        """Also used internally by DataArray so that the warning (if any)        is raised at the right stack level.        """        name_dict = either_dict_or_kwargs(name_dict, names, "rename")        for k in name_dict.keys():            if k not in self and k not in self.dims:                raise ValueError(                    f"cannot rename {k!r} because it is not a "                    "variable or dimension in this dataset"                )            create_dim_coord = False            new_k = name_dict[k]            if k in self.dims and new_k in self._coord_names:                coord_dims = self._variables[name_dict[k]].dims                if coord_dims == (k,):                    create_dim_coord = True            elif k in self._coord_names and new_k in self.dims:                coord_dims = self._variables[k].dims                if coord_dims == (new_k,):                    create_dim_coord = True            if create_dim_coord:                warnings.warn(                    f"rename {k!r} to {name_dict[k]!r} does not create an index "                    "anymore. Try using swap_dims instead or use set_index "                    "after rename to create an indexed coordinate.",                    UserWarning,                    stacklevel=3,                )        variables, coord_names, dims, indexes = self._rename_all(            name_dict=name_dict, dims_dict=name_dict        )        return self._replace(variables, coord_names, dims=dims, indexes=indexes)</ins>     def rename(         self: T_Dataset,         name_dict: Mapping[Any, Hashable] | None = None,


Dataset.rename_dims         DataArray.rename         """        name_dict = either_dict_or_kwargs(name_dict, names, "rename")        for k in name_dict.keys():            if k not in self and k not in self.dims:                raise ValueError(                    f"cannot rename {k!r} because it is not a "                    "variable or dimension in this dataset"                )        variables, coord_names, dims, indexes = self._rename_all(            name_dict=name_dict, dims_dict=name_dict        )        return self._replace(variables, coord_names, dims=dims, indexes=indexes)        return self._rename(name_dict=name_dict, **names)      def rename_dims(         self: T_Dataset,


"""Return a list of unique indexes, preserving order."""          unique_indexes: list[T_PandasOrXarrayIndex] = []        seen: set[T_PandasOrXarrayIndex] = set()        seen: set[int] = set()          for index in self._indexes.values():            if index not in seen:            index_id = id(index)            if index_id not in seen:                 unique_indexes.append(index)                seen.add(index)                seen.add(index_id)          return unique_indexes


"""         new_indexes = {}         new_index_vars = {}         for idx, coords in self.group_by_index():            if isinstance(idx, pd.Index):                convert_new_idx = True                dim = next(iter(coords.values())).dims[0]                if isinstance(idx, pd.MultiIndex):                    idx = PandasMultiIndex(idx, dim)                else:                    idx = PandasIndex(idx, dim)            else:                convert_new_idx = False             new_idx = idx.copy(deep=deep)             idx_vars = idx.create_variables(coords)            if convert_new_idx:                new_idx = cast(PandasIndex, new_idx).index             new_indexes.update({k: new_idx for k in coords})             new_index_vars.update(idx_vars)


variables, indexes = drop_coords(             coords, self._data._variables, self._data.xindexes         )<ins>        self._data._coord_names.intersection_update(variables)</ins>         self._data._variables = variables         self._data._indexes = indexes


f"other variables: {list(maybe_midx.index.names)!r}. "                 f"This will raise an error in the future. Use `.drop_vars({idx_coord_names!r})` before "                 "assigning new coordinate values.",                DeprecationWarning,                FutureWarning,                 stacklevel=4,             )             for k in idx_coord_names:


numpy.transpose         DataArray.transpose         """<ins>        # Raise error if list is passed as dims        if (len(dims) > 0) and (isinstance(dims[0], list)):            list_fix = [f"{repr(x)}" if isinstance(x, str) else f"{x}" for x in dims[0]]            raise TypeError(                f'transpose requires dims to be passed as multiple arguments. Expected `{", ".join(list_fix)}`. Received `{dims[0]}` instead'            )</ins>         # Use infix_dims to check once for missing dimensions         if len(dims) != 0:             _ = list(infix_dims(dims, self.dims, missing_dims))


and v.ndim > 0             and stackable(v.dims[-1])         )        new_vars[k] = decode_cf_variable(            k,            v,            concat_characters=concat_characters,            mask_and_scale=mask_and_scale,            decode_times=decode_times,            stack_char_dim=stack_char_dim,            use_cftime=use_cftime,            decode_timedelta=decode_timedelta,        )        try:            new_vars[k] = decode_cf_variable(                k,                v,                concat_characters=concat_characters,                mask_and_scale=mask_and_scale,                decode_times=decode_times,                stack_char_dim=stack_char_dim,                use_cftime=use_cftime,                decode_timedelta=decode_timedelta,            )        except Exception as e:            raise type(e)(f"Failed to decode variable {k!r}: {e}")         if decode_coords in [True, "coordinates", "all"]:             var_attrs = new_vars[k].attrs             if "coordinates" in var_attrs:


def _protect_dataset_variables_inplace(dataset, cache):     for name, variable in dataset.variables.items():        if name not in variable.dims:        if name not in dataset._indexes:             # no need to protect IndexVariable objects             data = indexing.CopyOnWriteArray(variable._data)             if cache:


return short_numpy_repr(array)     elif is_duck_array(internal_data):         return limit_lines(repr(array.data), limit=40)    elif array._in_memory or array.size < 1e5:    elif array._in_memory:         return short_numpy_repr(array)     else:         # internal xarray array type


Dataset.where, DataArray.where :         equivalent methods     """    from .dataset import Dataset     if keep_attrs is None:         keep_attrs = _get_keep_attrs(default=False)    if keep_attrs is True:        # keep the attributes of x, the second parameter, by default to        # be consistent with the `where` method of `DataArray` and `Dataset`        keep_attrs = lambda attrs, context: getattr(x, "attrs", {})      # alignment for three arguments is complicated, so don't support it yet    return apply_ufunc(    result = apply_ufunc(         duck_array_ops.where,         cond,         x,


keep_attrs=keep_attrs,     ) <ins>    # keep the attributes of x, the second parameter, by default to    # be consistent with the `where` method of `DataArray` and `Dataset`    # rebuild the attrs from x at each level of the output, which could be    # Dataset, DataArray, or Variable, and also handle coords    if keep_attrs is True:        if isinstance(y, Dataset) and not isinstance(x, Dataset):            # handle special case where x gets promoted to Dataset            result.attrs = {}            if getattr(x, "name", None) in result.data_vars:                result[x.name].attrs = getattr(x, "attrs", {})        else:            # otherwise, fill in global attrs and variable attrs (if they exist)            result.attrs = getattr(x, "attrs", {})            for v in getattr(result, "data_vars", []):                result[v].attrs = getattr(getattr(x, v, None), "attrs", {})        for c in getattr(result, "coords", []):            # always fill coord attrs of x            result[c].attrs = getattr(getattr(x, c, None), "attrs", {})    return result</ins>  @overload def polyval(


else:                 reshaped[key] = var         should_be_coords = set(window_dim) & set(self.obj.coords)        # should handle window_dim being unindexed        should_be_coords = (set(window_dim) & set(self.obj.coords)) | set(            self.obj.coords        )         result = reshaped.set_coords(should_be_coords)         if isinstance(self.obj, DataArray):             return self.obj._from_temp_dataset(result)


for name, variable in mapping.items():             if isinstance(variable, DataArray):                coords = variable._coords.copy()  # use private API for speed                indexes = dict(variable._indexes)                coords_ = variable._coords.copy()  # use private API for speed                indexes_ = dict(variable._indexes)                 # explicitly overwritten variables should take precedence                coords.pop(name, None)                indexes.pop(name, None)                append_all(coords, indexes)                coords_.pop(name, None)                indexes_.pop(name, None)                append_all(coords_, indexes_)              variable = as_variable(variable, name=name)             if name in indexes:


aligned = deep_align(         coerced, join=join, copy=False, indexes=indexes, fill_value=fill_value     )    collected = collect_variables_and_indexes(aligned)    collected = collect_variables_and_indexes(aligned, indexes=indexes)     prioritized = _get_priority_vars_and_indexes(aligned, priority_arg, compat=compat)     variables, out_indexes = merge_collected(collected, prioritized, compat=compat)     return variables, out_indexes


self, other = align(self, other, join=align_type, copy=False)  # type: ignore[assignment]         g = f if not reflexive else lambda x, y: f(y, x)         ds = self._calculate_binary_op(g, other, join=align_type)<ins>        keep_attrs = _get_keep_attrs(default=False)        if keep_attrs:            ds.attrs = self.attrs</ins>         return ds      def _inplace_binary_op(self: T_Dataset, other, f) -> T_Dataset:


self.level = level      def __array__(self, dtype: DTypeLike = None) -> np.ndarray:        if dtype is None:            dtype = self.dtype         if self.level is not None:            return self.array.get_level_values(self.level).values            return np.asarray(                self.array.get_level_values(self.level).values, dtype=dtype            )         else:             return super().__array__(dtype)


import pandas as pd  from xarray.core import dtypes, utilsfrom xarray.core.alignment import alignfrom xarray.core.alignment import align, reindex_variables from xarray.core.duck_array_ops import lazy_array_equiv from xarray.core.indexes import Index, PandasIndex from xarray.core.merge import (


elif opt == "all":                 concat_over.update(                    set(getattr(datasets[0], subset)) - set(datasets[0].dims)                    set().union(                        *list(set(getattr(d, subset)) - set(d.dims) for d in datasets)                    )                 )             elif opt == "minimal":                 pass


# determine dimensional coordinate names and a dict mapping name to DataArray def _parse_datasets(    datasets: Iterable[T_Dataset],) -> tuple[dict[Hashable, Variable], dict[Hashable, int], set[Hashable], set[Hashable]]:    datasets: list[T_Dataset],) -> tuple[    dict[Hashable, Variable],    dict[Hashable, int],    set[Hashable],    set[Hashable],    list[Hashable],]:     dims: set[Hashable] = set()     all_coord_names: set[Hashable] = set()     data_vars: set[Hashable] = set()  # list of data_vars     dim_coords: dict[Hashable, Variable] = {}  # maps dim name to variable     dims_sizes: dict[Hashable, int] = {}  # shared dimension sizes to expand variables    variables_order: dict[Hashable, Variable] = {}  # variables in order of appearance      for ds in datasets:         dims_sizes.update(ds.dims)         all_coord_names.update(ds.coords)         data_vars.update(ds.data_vars)        variables_order.update(ds.variables)          # preserves ordering of dimensions         for dim in ds.dims:


dim_coords[dim] = ds.coords[dim].variable         dims = dims | set(ds.dims)     return dim_coords, dims_sizes, all_coord_names, data_vars    return dim_coords, dims_sizes, all_coord_names, data_vars, list(variables_order)   def _dataset_concat(


coords: str | list[str],     compat: CompatOptions,     positions: Iterable[Iterable[int]] | None,    fill_value: object = dtypes.NA,    fill_value: Any = dtypes.NA,     join: JoinOptions = "outer",     combine_attrs: CombineAttrsOptions = "override", ) -> T_Dataset:


align(*datasets, join=join, copy=False, exclude=[dim], fill_value=fill_value)     )     dim_coords, dims_sizes, coord_names, data_names = _parse_datasets(datasets)    dim_coords, dims_sizes, coord_names, data_names, vars_order = _parse_datasets(        datasets    )     dim_names = set(dim_coords)     unlabeled_dims = dim_names - coord_names


# we've already verified everything is consistent; now, calculate     # shared dimension sizes so we can expand the necessary variables    def ensure_common_dims(vars):    def ensure_common_dims(vars, concat_dim_lengths):         # ensure each variable with the given name shares the same         # dimensions and the same shape for all of them except along the         # concat dimension


data = var.set_dims(dim).values                     yield PandasIndex(data, dim, coord_dtype=var.dtype)     # create concatenation index, needed for later reindexing    concat_index = list(range(sum(concat_dim_lengths)))     # stack up each variable and/or index to fill-out the dataset (in order)     # n.b. this loop preserves variable order, needed for groupby.    for name in datasets[0].variables:    for name in vars_order:         if name in concat_over and name not in result_indexes:            try:                vars = ensure_common_dims([ds[name].variable for ds in datasets])            except KeyError:                raise ValueError(f"{name!r} is not present in all datasets.")            # Try concatenate the indexes, concatenate the variables when no index            variables = []            variable_index = []            var_concat_dim_length = []            for i, ds in enumerate(datasets):                if name in ds.variables:                    variables.append(ds[name].variable)                    # add to variable index, needed for reindexing                    var_idx = [                        sum(concat_dim_lengths[:i]) + k                        for k in range(concat_dim_lengths[i])                    ]                    variable_index.extend(var_idx)                    var_concat_dim_length.append(len(var_idx))                else:                    # raise if coordinate not in all datasets                    if name in coord_names:                        raise ValueError(                            f"coordinate {name!r} not present in all datasets."                        )            vars = ensure_common_dims(variables, var_concat_dim_length)            # Try to concatenate the indexes, concatenate the variables when no index             # is found on all datasets.             indexes: list[Index] = list(get_indexes(name))             if indexes:


combined_var = concat_vars(                     vars, dim, positions, combine_attrs=combine_attrs                 )<ins>                # reindex if variable is not present in all datasets                if len(variable_index) < len(concat_index):                    combined_var = reindex_variables(                        variables={name: combined_var},                        dim_pos_indexers={                            dim: pd.Index(variable_index).get_indexer(concat_index)                        },                        fill_value=fill_value,                    )[name]</ins>                 result_vars[name] = combined_var          elif name in result_vars:


pool.join()      _merge_mapreduce_data(linter, all_mapreduce_data)    linter.stats = _merge_stats(all_stats)    linter.stats = _merge_stats([linter.stats] + all_stats)      # Insert stats data to local checkers.     for checker in linter.get_checkers():


do_exit=UNUSED_PARAM_SENTINEL,     ):  # pylint: disable=redefined-builtin         self._rcfile = None<ins>        self._output = None</ins>         self._version_asked = False         self._plugins = []         self.verbose = None


"rcfile": (self.cb_set_rcfile, True),                     "load-plugins": (self.cb_add_plugins, True),                     "verbose": (self.cb_verbose_mode, False),<ins>                    "output": (self.cb_set_output, True),</ins>                 },             )         except ArgumentPreprocessingError as ex:


"help": "Specify a configuration file to load.",                     },                 ),<ins>                (                    "output",                    {                        "action": "callback",                        "callback": Run._return_one,                        "group": "Commands",                        "type": "string",                        "metavar": "<file>",                        "help": "Specify an output file.",                    },                ),</ins>                 (                     "init-hook",                     {


# load plugin specific configuration.         linter.load_plugin_configuration()         linter.check(args)        score_value = linter.generate_reports()        if self._output:            try:                with open(self._output, "w") as output:                    linter.reporter.set_output(output)                    linter.check(args)                    score_value = linter.generate_reports()            except OSError as ex:                print(ex, file=sys.stderr)                sys.exit(32)        else:            linter.check(args)            score_value = linter.generate_reports()          if do_exit is not UNUSED_PARAM_SENTINEL:             warnings.warn(


"""callback for option preprocessing (i.e. before option parsing)"""         self._rcfile = value <ins>    def cb_set_output(self, name, value):        """callback for option preprocessing (i.e. before option parsing)"""        self._output = value</ins>     def cb_add_plugins(self, name, value):         """callback for option preprocessing (i.e. before option parsing)"""         self._plugins.extend(utils._splitstrip(value))


"help": "Specify a score threshold to be exceeded before program exits with error.",                 },             ),<ins>            (                "fail-on",                {                    "default": "",                    "type": "csv",                    "metavar": "<msg ids>",                    "help": "Return non-zero exit code if any of these messages/categories are detected,"                    " even if score is above --fail-under value. Syntax same as enable."                    " Messages specified are enabled, while categories only check already-enabled messages.",                },            ),</ins>             (                 "confidence",                 {


self.current_name = None         self.current_file = None         self.stats = None<ins>        self.fail_on_symbols = []</ins>         # init options         self._external_opts = options         self.options = options + PyLinter.make_options()


if not getattr(checker, "enabled", True):             self.disable(checker.name)     def enable_fail_on_messages(self):        """enable 'fail on' msgs        Convert values in config.fail_on (which might be msg category, msg id,        or symbol) to specific msgs, then enable and flag them for later.        """        fail_on_vals = self.config.fail_on        if not fail_on_vals:            return        fail_on_cats = set()        fail_on_msgs = set()        for val in fail_on_vals:            # If value is a cateogry, add category, else add message            if val in MSG_TYPES:                fail_on_cats.add(val)            else:                fail_on_msgs.add(val)        # For every message in every checker, if cat or msg flagged, enable check        for all_checkers in self._checkers.values():            for checker in all_checkers:                for msg in checker.messages:                    if msg.msgid in fail_on_msgs or msg.symbol in fail_on_msgs:                        # message id/symbol matched, enable and flag it                        self.enable(msg.msgid)                        self.fail_on_symbols.append(msg.symbol)                    elif msg.msgid[0] in fail_on_cats:                        # message starts with a cateogry value, flag (but do not enable) it                        self.fail_on_symbols.append(msg.symbol)    def any_fail_on_issues(self):        return any(x in self.fail_on_symbols for x in self.stats["by_msg"])     def disable_noerror_messages(self):         for msgcat, msgids in self.msgs_store._msgs_by_category.items():             # enable only messages with 'error' severity and above ('fatal')diff --git a/pylint/lint/run.py b/pylint/lint/run.py-- a/pylint/lint/run.py++ b/pylint/lint/run.py


# load plugin specific configuration.         linter.load_plugin_configuration() <ins>        # Now that plugins are loaded, get list of all fail_on messages, and enable them        linter.enable_fail_on_messages()</ins>         if self._output:             try:                 with open(self._output, "w") as output:


if linter.config.exit_zero:                 sys.exit(0)             else:                if score_value and score_value >= linter.config.fail_under:                if (                    score_value                    and score_value >= linter.config.fail_under                    # detected messages flagged by --fail-on prevent non-zero exit code                    and not linter.any_fail_on_issues()                ):                     sys.exit(0)                 sys.exit(self.linter.msg_status)


# Licensed under the GPL: https://www.gnu.org/licenses/old-licenses/gpl-2.0.html # For details: https://github.com/PyCQA/pylint/blob/master/LICENSE<ins>from typing import Tuple</ins>  from pkg_resources import DistributionNotFound, get_distribution


except DistributionNotFound:     __version__ = "2.8.2+" # Kept for compatibility reason, see https://github.com/PyCQA/pylint/issues/4399numversion = tuple(__version__.split("."))def get_numversion_from_version(v: str) -> Tuple:    """Kept for compatibility reason    See https://github.com/PyCQA/pylint/issues/4399    https://github.com/PyCQA/pylint/issues/4420,    """    v = v.replace("pylint-", "")    version = []    for n in v.split(".")[0:3]:        try:            version.append(int(n))        except ValueError:            num = ""            for c in n:                if c.isdigit():                    num += c                else:                    break            try:                version.append(int(num))            except ValueError:                version.append(0)    while len(version) != 3:        version.append(0)    return tuple(version)numversion = get_numversion_from_version(__version__)


return sys.stdin.read()  <ins>def _load_reporter_by_class(reporter_class: str) -> type:    qname = reporter_class    module_part = astroid.modutils.get_module_part(qname)    module = astroid.modutils.load_module_from_name(module_part)    class_name = qname.split(".")[-1]    return getattr(module, class_name)</ins> # Python Linter class #########################################################  MSGS = {


messages store / checkers / reporter / astroid manager"""         self.msgs_store = MessageDefinitionStore()         self.reporter = None        self._reporter_name = None        self._reporter_names = None         self._reporters = {}         self._checkers = collections.defaultdict(list)         self._pragma_lineno = {}


# Make sure to load the default reporter, because         # the option has been set before the plugins had been loaded.         if not self.reporter:            self._load_reporter()            self._load_reporters()      def load_plugin_modules(self, modnames):         """take a list of module names which are pylint plugins and load


if hasattr(module, "load_configuration"):                 module.load_configuration(self)     def _load_reporter(self):        name = self._reporter_name.lower()        if name in self._reporters:            self.set_reporter(self._reporters[name]())    def _load_reporters(self) -> None:        sub_reporters = []        output_files = []        with contextlib.ExitStack() as stack:            for reporter_name in self._reporter_names.split(","):                reporter_name, *reporter_output = reporter_name.split(":", 1)                reporter = self._load_reporter_by_name(reporter_name)                sub_reporters.append(reporter)                if reporter_output:                    (reporter_output,) = reporter_output                    # pylint: disable=consider-using-with                    output_file = stack.enter_context(open(reporter_output, "w"))                    reporter.set_output(output_file)                    output_files.append(output_file)            # Extend the lifetime of all opened output files            close_output_files = stack.pop_all().close        if len(sub_reporters) > 1 or output_files:            self.set_reporter(                reporters.MultiReporter(                    sub_reporters,                    close_output_files,                )            )         else:            try:                reporter_class = self._load_reporter_class()            except (ImportError, AttributeError) as e:                raise exceptions.InvalidReporterError(name) from e            else:                self.set_reporter(reporter_class())            self.set_reporter(sub_reporters[0])     def _load_reporter_class(self):        qname = self._reporter_name        module_part = astroid.modutils.get_module_part(qname)        module = astroid.modutils.load_module_from_name(module_part)        class_name = qname.split(".")[-1]        reporter_class = getattr(module, class_name)        return reporter_class    def _load_reporter_by_name(self, reporter_name: str) -> reporters.BaseReporter:        name = reporter_name.lower()        if name in self._reporters:            return self._reporters[name]()        try:            reporter_class = _load_reporter_by_class(reporter_name)        except (ImportError, AttributeError) as e:            raise exceptions.InvalidReporterError(name) from e        else:            return reporter_class()      def set_reporter(self, reporter):         """set the reporter used to display messages and reports"""


meth(value)                 return  # no need to call set_option, disable/enable methods do it         elif optname == "output-format":            self._reporter_name = value            self._reporter_names = value             # If the reporters are already available, load             # the reporter class.             if self._reporters:                self._load_reporter()                self._load_reporters()          try:             checkers.BaseTokenChecker.set_option(self, optname, value, action, optdict)diff --git a/pylint/reporters/__init__.py b/pylint/reporters/__init__.py-- a/pylint/reporters/__init__.py++ b/pylint/reporters/__init__.py


from pylint.reporters.base_reporter import BaseReporter from pylint.reporters.collecting_reporter import CollectingReporter from pylint.reporters.json_reporter import JSONReporter<ins>from pylint.reporters.multi_reporter import MultiReporter</ins> from pylint.reporters.reports_handler_mix_in import ReportsHandlerMixIn


utils.register_plugins(linter, __path__[0])  __all__ = ["BaseReporter", "ReportsHandlerMixIn", "JSONReporter", "CollectingReporter"]__all__ = [    "BaseReporter",    "ReportsHandlerMixIn",    "JSONReporter",    "CollectingReporter",    "MultiReporter",]diff --git a/pylint/reporters/multi_reporter.py b/pylint/reporters/multi_reporter.pynew file mode 100644-- /dev/null++ b/pylint/reporters/multi_reporter.py


<ins># Licensed under the GPL: https://www.gnu.org/licenses/old-licenses/gpl-2.0.html# For details: https://github.com/PyCQA/pylint/blob/master/LICENSEimport osfrom typing import IO, Any, AnyStr, Callable, List, Mapping, Optional, Unionfrom pylint.interfaces import IReporterfrom pylint.reporters.base_reporter import BaseReporterfrom pylint.reporters.ureports.nodes import BaseLayoutAnyFile = IO[AnyStr]AnyPath = Union[str, bytes, os.PathLike]PyLinter = Anyclass MultiReporter:    """Reports messages and layouts in plain text"""    __implements__ = IReporter    name = "_internal_multi_reporter"    # Note: do not register this reporter with linter.register_reporter as it is    #       not intended to be used directly like a regular reporter, but is    #       instead used to implement the    #       `--output-format=json:somefile.json,colorized`    #       multiple output formats feature    extension = ""    def __init__(        self,        sub_reporters: List[BaseReporter],        close_output_files: Callable[[], None],        output: Optional[AnyFile] = None,    ):        self._sub_reporters = sub_reporters        self.close_output_files = close_output_files        self._path_strip_prefix = os.getcwd() + os.sep        self._linter: Optional[PyLinter] = None        self.set_output(output)    def __del__(self):        self.close_output_files()    @property    def path_strip_prefix(self) -> str:        return self._path_strip_prefix    @property    def linter(self) -> Optional[PyLinter]:        return self._linter    @linter.setter    def linter(self, value: PyLinter) -> None:        self._linter = value        for rep in self._sub_reporters:            rep.linter = value    def handle_message(self, msg: str) -> None:        """Handle a new message triggered on the current file."""        for rep in self._sub_reporters:            rep.handle_message(msg)    # pylint: disable=no-self-use    def set_output(self, output: Optional[AnyFile] = None) -> None:        """set output stream"""        # MultiReporter doesn't have it's own output. This method is only        # provided for API parity with BaseReporter and should not be called        # with non-None values for 'output'.        if output is not None:            raise NotImplementedError("MultiReporter does not support direct output.")    def writeln(self, string: str = "") -> None:        """write a line in the output buffer"""        for rep in self._sub_reporters:            rep.writeln(string)    def display_reports(self, layout: BaseLayout) -> None:        """display results encapsulated in the layout tree"""        for rep in self._sub_reporters:            rep.display_reports(layout)    def display_messages(self, layout: BaseLayout) -> None:        """hook for displaying the messages of the reporter"""        for rep in self._sub_reporters:            rep.display_messages(layout)    def on_set_current_module(self, module: str, filepath: Optional[AnyPath]) -> None:        """hook called when a module starts to be analysed"""        for rep in self._sub_reporters:            rep.on_set_current_module(module, filepath)    def on_close(        self,        stats: Mapping[Any, Any],        previous_stats: Mapping[Any, Any],    ) -> None:        """hook called when a module finished analyzing"""        for rep in self._sub_reporters:            rep.on_close(stats, previous_stats)</ins>


import os import sys<ins>from typing import List, Pattern, Tuple</ins>  from astroid import modutils


return os.getcwd()  def _basename_in_ignore_list_re(base_name, ignore_list_re):    """Determines if the basename is matched in a regex ignorelist    :param str base_name: The basename of the file    :param list ignore_list_re: A collection of regex patterns to match against.        Successful matches are ignored.    :returns: `True` if the basename is ignored, `False` otherwise.    :rtype: bool    """def _is_in_ignore_list_re(element: str, ignore_list_re: List[Pattern]) -> bool:    """determines if the element is matched in a regex ignore-list"""     for file_pattern in ignore_list_re:        if file_pattern.match(base_name):        if file_pattern.match(element):             return True     return False  def expand_modules(files_or_modules, ignore_list, ignore_list_re):    """Take a list of files/modules/packages and return the list of tuple    (file, module name) which have to be actually checked."""def expand_modules(    files_or_modules: List[str],    ignore_list: List[str],    ignore_list_re: List[Pattern],    ignore_list_paths_re: List[Pattern],) -> Tuple[List[dict], List[dict]]:    """take a list of files/modules/packages and return the list of tuple    (file, module name) which have to be actually checked    """     result = []     errors = []     path = sys.path.copy()     for something in files_or_modules:         basename = os.path.basename(something)        if basename in ignore_list or _basename_in_ignore_list_re(            basename, ignore_list_re        if (            basename in ignore_list            or _is_in_ignore_list_re(os.path.basename(something), ignore_list_re)            or _is_in_ignore_list_re(something, ignore_list_paths_re)         ):             continue         module_path = get_python_path(something)


):                 if filepath == subfilepath:                     continue                if _basename_in_ignore_list_re(                if _is_in_ignore_list_re(                     os.path.basename(subfilepath), ignore_list_re                ):                ) or _is_in_ignore_list_re(subfilepath, ignore_list_paths_re):                     continue                 modpath = _modpath_from_file(                     subfilepath, is_namespace, path=additional_search_path                 )diff --git a/pylint/lint/pylinter.py b/pylint/lint/pylinter.py-- a/pylint/lint/pylinter.py++ b/pylint/lint/pylinter.py


" skipped. The regex matches against base names, not paths.",                 },             ),<ins>            (                "ignore-paths",                {                    "type": "regexp_csv",                    "metavar": "<pattern>[,<pattern>...]",                    "dest": "ignore_list_paths_re",                    "default": (),                    "help": "Add files or directories matching the regex patterns to the"                    " ignore-list. The regex matches against paths.",                },            ),</ins>             (                 "persistent",                 {


def _expand_files(self, modules):         """get modules and errors from a list of modules and handle errors"""         result, errors = expand_modules(            modules, self.config.black_list, self.config.black_list_re            modules,            self.config.black_list,            self.config.black_list_re,            self.config.ignore_list_paths_re,         )         for error in errors:             message = modname = error["mod"]


if isinstance(node, astroid.Instance):                 node = node._proxied             if (                isinstance(node, astroid.ClassDef)                isinstance(node, (astroid.ClassDef, astroid.Name, astroid.Subscript))                 and hasattr(node, "name")                 and not self.has_node(node)             ):diff --git a/pylint/pyreverse/inspector.py b/pylint/pyreverse/inspector.py-- a/pylint/pyreverse/inspector.py++ b/pylint/pyreverse/inspector.py


# the name has been defined as 'global' in the frame and belongs             # there.             frame = node.root()        try:            if not hasattr(frame, "locals_type"):                # If the frame doesn't have a locals_type yet,                # it means it wasn't yet visited. Visit it now                # to add what's missing from it.                if isinstance(frame, astroid.ClassDef):                    self.visit_classdef(frame)                elif isinstance(frame, astroid.FunctionDef):                    self.visit_functiondef(frame)                else:                    self.visit_module(frame)            current = frame.locals_type[node.name]            values = set(node.infer())            frame.locals_type[node.name] = list(set(current) | values)        except astroid.InferenceError:            pass        if not hasattr(frame, "locals_type"):            # If the frame doesn't have a locals_type yet,            # it means it wasn't yet visited. Visit it now            # to add what's missing from it.            if isinstance(frame, astroid.ClassDef):                self.visit_classdef(frame)            elif isinstance(frame, astroid.FunctionDef):                self.visit_functiondef(frame)            else:                self.visit_module(frame)        current = frame.locals_type[node.name]        frame.locals_type[node.name] = list(set(current) | utils.infer_node(node))      @staticmethod     def handle_assignattr_type(node, parent):


handle instance_attrs_type         """        try:            values = set(node.infer())            current = set(parent.instance_attrs_type[node.attrname])            parent.instance_attrs_type[node.attrname] = list(current | values)        except astroid.InferenceError:            pass        current = set(parent.instance_attrs_type[node.attrname])        parent.instance_attrs_type[node.attrname] = list(            current | utils.infer_node(node)        )      def visit_import(self, node):         """visit an astroid.Import nodediff --git a/pylint/pyreverse/utils.py b/pylint/pyreverse/utils.py-- a/pylint/pyreverse/utils.py++ b/pylint/pyreverse/utils.py


import os import re import sys<ins>from typing import Optional, Unionimport astroid</ins>  RCFILE = ".pyreverserc"


if methods[1] is not None:             return methods[1](node)         return Nonedef get_annotation_label(ann: Union[astroid.Name, astroid.Subscript]) -> str:    label = ""    if isinstance(ann, astroid.Subscript):        label = ann.as_string()    elif isinstance(ann, astroid.Name):        label = ann.name    return labeldef get_annotation(    node: Union[astroid.AssignAttr, astroid.AssignName]) -> Optional[Union[astroid.Name, astroid.Subscript]]:    """return the annotation for `node`"""    ann = None    if isinstance(node.parent, astroid.AnnAssign):        ann = node.parent.annotation    elif isinstance(node, astroid.AssignAttr):        init_method = node.parent.parent        try:            annotations = dict(zip(init_method.locals, init_method.args.annotations))            ann = annotations.get(node.parent.value.name)        except AttributeError:            pass    else:        return ann    try:        default, *_ = node.infer()    except astroid.InferenceError:        default = ""    label = get_annotation_label(ann)    if ann:        label = (            rf"Optional[{label}]"            if getattr(default, "value", "value") is None            and not label.startswith("Optional")            else label        )    if label:        ann.name = label    return anndef infer_node(node: Union[astroid.AssignAttr, astroid.AssignName]) -> set:    """Return a set containing the node annotation if it exists    otherwise return a set of the inferred types using the NodeNG.infer method"""    ann = get_annotation(node)    if ann:        return {ann}    try:        return set(node.infer())    except astroid.InferenceError:        return set()diff --git a/pylint/pyreverse/writer.py b/pylint/pyreverse/writer.py-- a/pylint/pyreverse/writer.py++ b/pylint/pyreverse/writer.py


import os  from pylint.graph import DotBackendfrom pylint.pyreverse.utils import is_exceptionfrom pylint.pyreverse.utils import get_annotation_label, is_exception from pylint.pyreverse.vcgutils import VCGPrinter


if not self.config.only_classnames:             label = r"{}|{}\l|".format(label, r"\l".join(obj.attrs))             for func in obj.methods:                return_type = (                    f": {get_annotation_label(func.returns)}" if func.returns else ""                )                 if func.args.args:                    args = [arg.name for arg in func.args.args if arg.name != "self"]                    args = [arg for arg in func.args.args if arg.name != "self"]                 else:                     args = []                label = r"{}{}({})\l".format(label, func.name, ", ".join(args))                annotations = dict(zip(args, func.args.annotations[1:]))                for arg in args:                    annotation_label = ""                    ann = annotations.get(arg)                    if ann:                        annotation_label = get_annotation_label(ann)                    annotations[arg] = annotation_label                args = ", ".join(                    f"{arg.name}: {ann}" if ann else f"{arg.name}"                    for arg, ann in annotations.items()                )                label = fr"{label}{func.name}({args}){return_type}\l"             label = "{%s}" % label         if is_exception(obj.node):             return dict(fontcolor="red", label=label, shape="record")


self._type_annotation_names.append(type_annotation.name)             return         if isinstance(type_annotation, astroid.Attribute):            self._store_type_annotation_node(type_annotation.expr)            return         if not isinstance(type_annotation, astroid.Subscript):             return diff --git a/pylint/constants.py b/pylint/constants.py-- a/pylint/constants.py++ b/pylint/constants.py


# Licensed under the GPL: https://www.gnu.org/licenses/old-licenses/gpl-2.0.html # For details: https://github.com/PyCQA/pylint/blob/master/LICENSE <ins>import platform</ins> import sys  import astroid


PY39_PLUS = sys.version_info[:2] >= (3, 9) PY310_PLUS = sys.version_info[:2] >= (3, 10) <ins>IS_PYPY = platform.python_implementation() == "PyPy"</ins>  PY_EXTS = (".py", ".pyc", ".pyo", ".pyw", ".so", ".dll")


import pickle import sys <ins>import appdirs</ins> from pylint.config.configuration_mixin import ConfigurationMixIn from pylint.config.find_default_config_files import find_default_config_files from pylint.config.man_help_formatter import _ManHelpFormatter


elif USER_HOME == "~":     PYLINT_HOME = ".pylint.d" else:    PYLINT_HOME = os.path.join(USER_HOME, ".pylint.d")    PYLINT_HOME = appdirs.user_cache_dir("pylint")    old_home = os.path.join(USER_HOME, ".pylint.d")    if os.path.exists(old_home):        print(            f"PYLINTHOME is now '{PYLINT_HOME}' but obsolescent '{old_home}' is found; "            "you can safely remove the latter",            file=sys.stderr,        )   def _get_pdata_path(base_name, recurs):


signature_lines = set(             chain(                 *(                    range(func.fromlineno, func.body[0].lineno)                    range(                        func.fromlineno,                        func.body[0].lineno if func.body else func.tolineno + 1,                    )                     for func in functions                    if func.body                 )             )         )


self.add_message("import-error", args=repr(dotted_modname), node=importnode)         return None     def _add_imported_module(self, node, importedmodname):    def _add_imported_module(        self, node: Union[astroid.Import, astroid.ImportFrom], importedmodname: str    ) -> None:         """notify an imported module, used to analyze dependencies"""         module_file = node.root().file         context_name = node.root().name


except ImportError:             pass <ins>        in_type_checking_block = (            isinstance(node.parent, astroid.If) and node.parent.is_typing_guard()        )</ins>         if context_name == importedmodname:             self.add_message("import-self", node=node)


# update import graph             self.import_graph[context_name].add(importedmodname)            if not self.linter.is_message_enabled("cyclic-import", line=node.lineno):            if (                not self.linter.is_message_enabled("cyclic-import", line=node.lineno)                or in_type_checking_block            ):                 self._excluded_edges[context_name].add(importedmodname)      def _check_preferred_module(self, node, mod_path):


if config_file is None:             config_file = self.config_file         if config_file is not None:            config_file = os.path.expanduser(config_file)            config_file = os.path.expandvars(os.path.expanduser(config_file))             if not os.path.exists(config_file):                 raise OSError(f"The config file {config_file} doesn't exist!")


)  import astroid<ins>from astroid.node_classes import NodeNG</ins>  from pylint.checkers import BaseChecker, MapReduceMixin, table_lines_from_stats from pylint.interfaces import IRawChecker


}         current_line_is_import = False     if ignore_signatures:        functions = [            n            for n in tree.body            if isinstance(n, (astroid.FunctionDef, astroid.AsyncFunctionDef))        ]        def _get_functions(functions: List[NodeNG], tree: NodeNG) -> List[NodeNG]:            """Recursively get all functions including nested in the classes from the tree."""            for node in tree.body:                if isinstance(node, (astroid.FunctionDef, astroid.AsyncFunctionDef)):                    functions.append(node)                if isinstance(                    node,                    (astroid.ClassDef, astroid.FunctionDef, astroid.AsyncFunctionDef),                ):                    _get_functions(functions, node)            return functions        functions = _get_functions([], tree)         signature_lines = set(             chain(                 *(


def run(self) -> None:         """start looking for similarities and display results on stdout"""<ins>        if self.min_lines == 0:            return</ins>         self._display_sims(self._compute_sims())      def _compute_sims(self) -> List[Tuple[int, Set[LinesChunkLimits_T]]]:


\s+         )?         (\w+)                   # Parameter name        (\*{{0,2}}\w+)          # Parameter name with potential asterisks         \s*                     # whitespace         :                       # final colon         """


re_param_line = re.compile(         fr"""        \s*  \*{{0,2}}(\w+)             # identifier potentially with asterisks        \s*  (\*{{0,2}}\w+)             # identifier potentially with asterisks         \s*  ( [(]             {re_multiple_type}             (?:,\s+optional)?


re_param_line = re.compile(         fr"""        \s*  (\w+)                                                          # identifier        \s*  (\*{{0,2}}\w+)                                                 # identifier with potential asterisks         \s*  :         \s*  (?:({GoogleDocstring.re_multiple_type})(?:,\s+optional)?)?     # optional type declaration         \s* (.*)                                                            # optional descriptiondiff --git a/pylint/extensions/docparams.py b/pylint/extensions/docparams.py-- a/pylint/extensions/docparams.py++ b/pylint/extensions/docparams.py


}          if arguments_node.vararg is not None:            expected_argument_names.add(arguments_node.vararg)            not_needed_type_in_docstring.add(arguments_node.vararg)            expected_argument_names.add(f"*{arguments_node.vararg}")            not_needed_type_in_docstring.add(f"*{arguments_node.vararg}")         if arguments_node.kwarg is not None:            expected_argument_names.add(arguments_node.kwarg)            not_needed_type_in_docstring.add(arguments_node.kwarg)            expected_argument_names.add(f"**{arguments_node.kwarg}")            not_needed_type_in_docstring.add(f"**{arguments_node.kwarg}")         params_with_doc, params_with_type = doc.match_param_docs()         # Tolerate no parameter documentation at all.         if not params_with_doc and not params_with_type and accept_no_param_doc:diff --git a/pylint/reporters/text.py b/pylint/reporters/text.py-- a/pylint/reporters/text.py++ b/pylint/reporters/text.py


:param style: the message's style elements, this will be deprecated     :param kwargs: used to accept `color` parameter while it is being deprecated    :param **kwargs: used to accept `color` parameter while it is being deprecated      :return: the ansi escaped string     """


"""Utility methods for docstring checking."""  import refrom typing import Listfrom typing import List, Set, Tuple  import astroid from astroid import nodes


re_param_line = re.compile(         fr"""        \s*  (\*{{0,2}}\w+)                                                 # identifier with potential asterisks        \s*  :        \s*  (?:({GoogleDocstring.re_multiple_type})(?:,\s+optional)?)?     # optional type declaration        \s*  (\*{{0,2}}\w+)(\s?(:|\n))                                      # identifier with potential asterisks        \s*  (?:({GoogleDocstring.re_multiple_type})(?:,\s+optional)?\n)?   # optional type declaration         \s* (.*)                                                            # optional description     """,         re.X | re.S,


supports_yields = True <ins>    def match_param_docs(self) -> Tuple[Set[str], Set[str]]:        """Matches parameter documentation section to parameter documentation rules"""        params_with_doc = set()        params_with_type = set()        entries = self._parse_section(self.re_param_section)        print(entries)        entries.extend(self._parse_section(self.re_keyword_param_section))        for entry in entries:            match = self.re_param_line.match(entry)            if not match:                continue            # check if parameter has description only            re_only_desc = re.match(r"\s*  (\*{0,2}\w+)\s*:?\n", entry)            if re_only_desc:                param_name = match.group(1)                param_desc = match.group(2)                param_type = None            else:                param_name = match.group(1)                param_type = match.group(3)                param_desc = match.group(4)            if param_type:                params_with_type.add(param_name)            if param_desc:                params_with_doc.add(param_name)        return params_with_doc, params_with_type</ins>     @staticmethod     def min_section_indent(section_match):         return len(section_match.group(1))


else:             readlines = stream.readlines  # type: ignore[assignment] # hint parameter is incorrectly typed as non-optional         try:            active_lines: List[str] = []            if hasattr(self, "linter"):                # Remove those lines that should be ignored because of disables                for index, line in enumerate(readlines()):                    if self.linter._is_one_message_enabled("R0801", index + 1):  # type: ignore[attr-defined]                        active_lines.append(line)            else:                active_lines = readlines()             self.linesets.append(                 LineSet(                     streamid,                    readlines(),                    active_lines,                     self.ignore_comments,                     self.ignore_docstrings,                     self.ignore_imports,


"metavar": "<python_expression>",                     "group": "Reports",                     "level": 1,                    "default": "0 if fatal else 10.0 - ((float(5 * error + warning + refactor + "                    "convention) / statement) * 10)",                    "default": "max(0, 0 if fatal else 10.0 - ((float(5 * error + warning + refactor + "                    "convention) / statement) * 10))",                     "help": "Python expression which should return a score less "                     "than or equal to 10. You have access to the variables 'fatal', "                     "'error', 'warning', 'refactor', 'convention', and 'info' which "


import os import sysfrom typing import List, Optional  from pylint.__pkginfo__ import __version__  # pylint: disable=import-outside-toplevel  def run_pylint():def run_pylint(*, arguments: Optional[List[str]] = None):    """Run pylint    Arguments can be a list of strings normally supplied as arguments on the command line    """     from pylint.lint import Run as PylintRun      try:        PylintRun(sys.argv[1:])        PylintRun(arguments or sys.argv[1:])     except KeyboardInterrupt:         sys.exit(1)


EpylintRun()  def run_pyreverse():    """run pyreverse"""def run_pyreverse(*, arguments: Optional[List[str]] = None):    """Run pyreverse    Arguments can be a list of strings normally supplied as arguments on the command line    """     from pylint.pyreverse.main import Run as PyreverseRun     PyreverseRun(sys.argv[1:])    PyreverseRun(arguments or sys.argv[1:]) def run_symilar(*, arguments: Optional[List[str]] = None):    """Run symilar def run_symilar():    """run symilar"""    Arguments can be a list of strings normally supplied as arguments on the command line    """     from pylint.checkers.similar import Run as SimilarRun     SimilarRun(sys.argv[1:])    SimilarRun(arguments or sys.argv[1:])   def modify_sys_path() -> None:


from pylint.lint import PyLinter from pylint.utils import get_rst_title <del># Some modules have been renamed and deprecated under their old names.# Skip documenting these modules since:# 1) They are deprecated, why document them moving forward?# 2) We can't load the deprecated module and the newly renamed module at the# same time without getting naming conflictsDEPRECATED_MODULES = ["check_docs"]  # ==> docparams</del>  def builder_inited(app):     """Output full documentation in ReST format for all extension modules"""


doc_files = {}     for filename in os.listdir(ext_path):         name, ext = os.path.splitext(filename)        if name[0] == "_" or name in DEPRECATED_MODULES:        if name[0] == "_":             continue         if ext == ".py":             modules.append(f"pylint.extensions.{name}")diff --git a/pylint/extensions/check_docs.py b/pylint/extensions/check_docs.pydeleted file mode 100644-- a/pylint/extensions/check_docs.py++ /dev/null


# Copyright (c) 2014-2015 Bruno Daniel <bruno.daniel@blue-yonder.com># Copyright (c) 2015-2016, 2018, 2020 Claudiu Popa <pcmanticore@gmail.com># Copyright (c) 2016 Ashley Whetter <ashley@awhetter.co.uk># Copyright (c) 2020 hippo91 <guillaume.peillex@gmail.com># Copyright (c) 2021 Pierre Sassoulas <pierre.sassoulas@gmail.com># Copyright (c) 2021 Marc Mueller <30130371+cdce8p@users.noreply.github.com># Licensed under the GPL: https://www.gnu.org/licenses/old-licenses/gpl-2.0.html# For details: https://github.com/PyCQA/pylint/blob/main/LICENSEimport warningsfrom typing import TYPE_CHECKINGfrom pylint.extensions import docparamsif TYPE_CHECKING:    from pylint.lint import PyLinterdef register(linter: "PyLinter") -> None:    warnings.warn(        "This plugin is deprecated, use pylint.extensions.docparams instead.",        DeprecationWarning,    )    linter.register_checker(docparams.DocstringParameterChecker(linter))diff --git a/pylint/lint/run.py b/pylint/lint/run.py-- a/pylint/lint/run.py++ b/pylint/lint/run.py


def cb_enable_all_extensions(self, option_name: str, value: None) -> None:         """Callback to load and enable all available extensions"""         for filename in os.listdir(os.path.dirname(extensions.__file__)):            # pylint: disable=fixme            # TODO: Remove the check for deprecated check_docs after the extension has been removed            if (                filename.endswith(".py")                and not filename.startswith("_")                and not filename.startswith("check_docs")            ):            if filename.endswith(".py") and not filename.startswith("_"):                 extension_name = f"pylint.extensions.{filename[:-3]}"                 if extension_name not in self._plugins:                     self._plugins.append(extension_name)


13: string_format 14: string_constant 15: stdlib16: python316: python3 (This one was deleted but needs to be reserved for consistency with old messages) 17: refactoring . . . 24: non-ascii-names 25: unicode26-50: not yet used: reserved for future internal checkers.26: unsupported_version27-50: not yet used: reserved for future internal checkers. This file is not updated. Use    script/get_unused_message_id_category.py to get the next free checker id.diff --git a/pylint/checkers/unsupported_version.py b/pylint/checkers/unsupported_version.py-- a/pylint/checkers/unsupported_version.py++ b/pylint/checkers/unsupported_version.py


__implements__ = (IAstroidChecker,)     name = "unsupported_version"     msgs = {        "W1601": (        "W2601": (             "F-strings are not supported by all versions included in the py-version setting",             "using-f-string-in-unsupported-version",             "Used when the py-version set by the user is lower than 3.6 and pylint encounters "             "a f-string.",         ),        "W1602": (        "W2602": (             "typing.final is not supported by all versions included in the py-version setting",             "using-final-decorator-in-unsupported-version",             "Used when the py-version set by the user is lower than 3.8 and pylint encounters "diff --git a/pylint/constants.py b/pylint/constants.py-- a/pylint/constants.py++ b/pylint/constants.py


# For details: https://github.com/PyCQA/pylint/blob/main/LICENSE import platform import sysfrom typing import Dictfrom typing import Dict, List, NamedTuple, Tuple  import astroid import platformdirs


"class_const": "class constant",     "inlinevar": "inline iteration", }class DeletedMessage(NamedTuple):    msgid: str    symbol: str    old_names: List[Tuple[str, str]] = []DELETED_MSGID_PREFIXES = [    16,  # the PY3K+ checker, see https://github.com/PyCQA/pylint/pull/4942]DELETED_MESSAGES = [    # Everything until the next comment is from the    # PY3K+ checker, see https://github.com/PyCQA/pylint/pull/4942    DeletedMessage("W1601", "apply-builtin"),    DeletedMessage("E1601", "print-statement"),    DeletedMessage("E1602", "parameter-unpacking"),    DeletedMessage(        "E1603", "unpacking-in-except", [("W0712", "old-unpacking-in-except")]    ),    DeletedMessage("E1604", "old-raise-syntax", [("W0121", "old-old-raise-syntax")]),    DeletedMessage("E1605", "backtick", [("W0333", "old-backtick")]),    DeletedMessage("E1609", "import-star-module-level"),    DeletedMessage("W1601", "apply-builtin"),    DeletedMessage("W1602", "basestring-builtin"),    DeletedMessage("W1603", "buffer-builtin"),    DeletedMessage("W1604", "cmp-builtin"),    DeletedMessage("W1605", "coerce-builtin"),    DeletedMessage("W1606", "execfile-builtin"),    DeletedMessage("W1607", "file-builtin"),    DeletedMessage("W1608", "long-builtin"),    DeletedMessage("W1609", "raw_input-builtin"),    DeletedMessage("W1610", "reduce-builtin"),    DeletedMessage("W1611", "standarderror-builtin"),    DeletedMessage("W1612", "unicode-builtin"),    DeletedMessage("W1613", "xrange-builtin"),    DeletedMessage("W1614", "coerce-method"),    DeletedMessage("W1615", "delslice-method"),    DeletedMessage("W1616", "getslice-method"),    DeletedMessage("W1617", "setslice-method"),    DeletedMessage("W1618", "no-absolute-import"),    DeletedMessage("W1619", "old-division"),    DeletedMessage("W1620", "dict-iter-method"),    DeletedMessage("W1621", "dict-view-method"),    DeletedMessage("W1622", "next-method-called"),    DeletedMessage("W1623", "metaclass-assignment"),    DeletedMessage(        "W1624", "indexing-exception", [("W0713", "old-indexing-exception")]    ),    DeletedMessage("W1625", "raising-string", [("W0701", "old-raising-string")]),    DeletedMessage("W1626", "reload-builtin"),    DeletedMessage("W1627", "oct-method"),    DeletedMessage("W1628", "hex-method"),    DeletedMessage("W1629", "nonzero-method"),    DeletedMessage("W1630", "cmp-method"),    DeletedMessage("W1632", "input-builtin"),    DeletedMessage("W1633", "round-builtin"),    DeletedMessage("W1634", "intern-builtin"),    DeletedMessage("W1635", "unichr-builtin"),    DeletedMessage(        "W1636", "map-builtin-not-iterating", [("W1631", "implicit-map-evaluation")]    ),    DeletedMessage("W1637", "zip-builtin-not-iterating"),    DeletedMessage("W1638", "range-builtin-not-iterating"),    DeletedMessage("W1639", "filter-builtin-not-iterating"),    DeletedMessage("W1640", "using-cmp-argument"),    DeletedMessage("W1641", "eq-without-hash"),    DeletedMessage("W1642", "div-method"),    DeletedMessage("W1643", "idiv-method"),    DeletedMessage("W1644", "rdiv-method"),    DeletedMessage("W1645", "exception-message-attribute"),    DeletedMessage("W1646", "invalid-str-codec"),    DeletedMessage("W1647", "sys-max-int"),    DeletedMessage("W1648", "bad-python3-import"),    DeletedMessage("W1649", "deprecated-string-function"),    DeletedMessage("W1650", "deprecated-str-translate-call"),    DeletedMessage("W1651", "deprecated-itertools-function"),    DeletedMessage("W1652", "deprecated-types-field"),    DeletedMessage("W1653", "next-method-defined"),    DeletedMessage("W1654", "dict-items-not-iterating"),    DeletedMessage("W1655", "dict-keys-not-iterating"),    DeletedMessage("W1656", "dict-values-not-iterating"),    DeletedMessage("W1657", "deprecated-operator-function"),    DeletedMessage("W1658", "deprecated-urllib-function"),    DeletedMessage("W1659", "xreadlines-attribute"),    DeletedMessage("W1660", "deprecated-sys-function"),    DeletedMessage("W1661", "exception-escape"),    DeletedMessage("W1662", "comprehension-escape"),    # https://github.com/PyCQA/pylint/pull/3578    DeletedMessage("W0312", "mixed-indentation"),    # https://github.com/PyCQA/pylint/pull/3577    DeletedMessage(        "C0326",        "bad-whitespace",        [            ("C0323", "no-space-after-operator"),            ("C0324", "no-space-after-comma"),            ("C0322", "no-space-before-operator"),        ],    ),    # https://github.com/PyCQA/pylint/pull/3571    DeletedMessage("C0330", "bad-continuation"),]diff --git a/script/get_unused_message_id_category.py b/script/get_unused_message_id_category.py-- a/script/get_unused_message_id_category.py++ b/script/get_unused_message_id_category.py


from typing import List  from pylint.checkers import initialize as initialize_checkers<ins>from pylint.constants import DELETED_MSGID_PREFIXES</ins> from pylint.extensions import initialize as initialize_extensions from pylint.lint.pylinter import PyLinter


def get_next_code_category(message_ids: List[str]) -> int:     categories = sorted({int(i[:2]) for i in message_ids})<ins>    # We add the prefixes for deleted checkers    categories += DELETED_MSGID_PREFIXES</ins>     for i in categories:         if i + 1 not in categories:             return i + 1


notes = "|".join(re.escape(note) for note in self.config.notes)         if self.config.notes_rgx:            regex_string = rf"#\s*({notes}|{self.config.notes_rgx})\b"            regex_string = rf"#\s*({notes}|{self.config.notes_rgx})(?=(:|\s|\Z))"         else:            regex_string = rf"#\s*({notes})\b"            regex_string = rf"#\s*({notes})(?=(:|\s|\Z))"          self._fixme_pattern = re.compile(regex_string, re.I)


from astroid import nodes  from pylint.pyreverse.printer import EdgeType, Layout, NodeProperties, NodeType, Printerfrom pylint.pyreverse.utils import check_graphviz_availability, get_annotation_labelfrom pylint.pyreverse.utils import get_annotation_label  ALLOWED_CHARSETS: FrozenSet[str] = frozenset(("utf-8", "iso-8859-1", "latin1")) SHAPES: Dict[NodeType, str] = {


with open(dot_sourcepath, "w", encoding="utf8") as outfile:             outfile.writelines(self.lines)         if target not in graphviz_extensions:            check_graphviz_availability()             use_shell = sys.platform == "win32"             subprocess.call(                 ["dot", "-T", target, dot_sourcepath, "-o", outputfile],diff --git a/pylint/pyreverse/main.py b/pylint/pyreverse/main.py-- a/pylint/pyreverse/main.py++ b/pylint/pyreverse/main.py


from pylint.pyreverse import writer from pylint.pyreverse.diadefslib import DiadefsHandler from pylint.pyreverse.inspector import Linker, project_from_filesfrom pylint.pyreverse.utils import check_graphviz_availability, insert_default_optionsfrom pylint.pyreverse.utils import (    check_graphviz_availability,    check_if_graphviz_supports_format,    insert_default_options,)DIRECTLY_SUPPORTED_FORMATS = (    "dot",    "vcg",    "puml",    "plantuml",    "mmd",    "html",)  OPTIONS = (     (


action="store",             default="dot",             metavar="<format>",            help="create a *.<format> output file if format available.",            help=(                f"create a *.<format> output file if format is available. Available formats are: {', '.join(DIRECTLY_SUPPORTED_FORMATS)}. "                f"Any other format will be tried to create by means of the 'dot' command line tool, which requires a graphviz installation."            ),         ),     ),     (


super().__init__(usage=__doc__)         insert_default_options()         args = self.load_command_line_configuration(args)        if self.config.output_format not in (            "dot",            "vcg",            "puml",            "plantuml",            "mmd",            "html",        ):        if self.config.output_format not in DIRECTLY_SUPPORTED_FORMATS:             check_graphviz_availability()            print(                f"Format {self.config.output_format} is not supported natively. Pyreverse will try to generate it using Graphviz..."            )            check_if_graphviz_supports_format(self.config.output_format)          sys.exit(self.run(args)) diff --git a/pylint/pyreverse/utils.py b/pylint/pyreverse/utils.py-- a/pylint/pyreverse/utils.py++ b/pylint/pyreverse/utils.py


import os import re import shutil<ins>import subprocess</ins> import sys from typing import Optional, Union


from *.dot or *.gv into the final output format.     """     if shutil.which("dot") is None:        print("'Graphviz' needs to be installed for your chosen output format.")        sys.exit(32)def check_if_graphviz_supports_format(output_format: str) -> None:    """Check if the ``dot`` command supports the requested output format.    This is needed if image output is desired and ``dot`` is used to convert    from *.gv into the final output format.    """    dot_output = subprocess.run(        ["dot", "-T?"], capture_output=True, check=False, encoding="utf-8"    )    match = re.match(        pattern=r".*Use one of: (?P<formats>(\S*\s?)+)",        string=dot_output.stderr.strip(),    )    if not match:        print(            "Unable to determine Graphviz supported output formats. "            "Pyreverse will continue, but subsequent error messages "            "regarding the output format may come from Graphviz directly."        )        return    supported_formats = match.group("formats")    if output_format not in supported_formats.split():         print(            "The requested output format is currently not available.\n"            "Please install 'Graphviz' to have other output formats "            "than 'dot' or 'vcg'."            f"Format {output_format} is not supported by Graphviz. It supports: {supported_formats}"         )         sys.exit(32)


def __gt__(self, other):         """Permit to sort a list of Checker by name."""        return f"{self.name}{self.msgs}" > (f"{other.name}{other.msgs}")        return f"{self.name}{self.msgs}" > f"{other.name}{other.msgs}"    def __eq__(self, other):        """Permit to assert Checkers are equal."""        return f"{self.name}{self.msgs}" == f"{other.name}{other.msgs}"    def __hash__(self):        """Make Checker hashable."""        return hash(f"{self.name}{self.msgs}")      def __repr__(self):         status = "Checker" if self.enabled else "Disabled checker"


import re import string import warningsfrom collections.abc import Callable, Iterablefrom collections.abc import Iterable from functools import lru_cache, partial from re import Matchfrom typing import TypeVarfrom typing import Callable, TypeVar  import _string import astroid.objects from astroid import TooManyLevelsError, nodes from astroid.context import InferenceContext from pylint.checkers.base_checker import BaseChecker from pylint.constants import TYPING_TYPE_CHECKS_GUARDS  COMP_NODE_TYPES = (


)  T_Node = TypeVar("T_Node", bound=nodes.NodeNG)<ins>CheckerT = TypeVar("CheckerT", bound=BaseChecker)AstCallback = Callable[[CheckerT, T_Node], None]</ins>   class NoSuchArgumentError(Exception):


return False  def check_messages(*messages: str) -> Callable:    """Decorator to store messages that are handled by a checker method."""def only_required_for_messages(*messages: str) -> Callable[[AstCallback], AstCallback]:    """Decorator to store messages that are handled by a checker method as an    attribute of the function object.    This information is used by ``ASTWalker`` to decide whether to call the decorated    method or not. If none of the messages is enabled, the method will be skipped.    Therefore, the list of messages must be well maintained at all times!    This decorator only has an effect on ``visit_*`` and ``leave_*`` methods    of a class inheriting from ``BaseChecker`` and implementing ``IAstroidChecker``.    """      def store_messages(func):         func.checks_msgs = messages


return store_messages  <ins>def check_messages(*messages: str) -> Callable[[AstCallback], AstCallback]:    """Kept for backwards compatibility, deprecated.    Use only_required_for_messages instead, which conveys the intent of the decorator much clearer.    """    warnings.warn(        "utils.check_messages will be removed in favour of calling "        "utils.only_required_for_messages in pylint 3.0",        DeprecationWarning,    )    return only_required_for_messages(*messages)</ins> class IncompleteFormatString(Exception):     """A format string ended in the middle of a format specifier."""


import sys import warnings from collections import defaultdictfrom collections.abc import Generator, Iterablefrom collections.abc import Callable, Generator, Iterable from getopt import getopt from io import BufferedIOBase, BufferedReader, BytesIO from itertools import chain, groupby


readlines = decoding_stream(stream, encoding).readlines         else:             readlines = stream.readlines  # type: ignore[assignment] # hint parameter is incorrectly typed as non-optional         try:            active_lines: list[str] = []            if hasattr(self, "linter"):                # Remove those lines that should be ignored because of disables                for index, line in enumerate(readlines()):                    if self.linter._is_one_message_enabled("R0801", index + 1):  # type: ignore[attr-defined]                        active_lines.append(line)            else:                active_lines = readlines()            self.linesets.append(                LineSet(                    streamid,                    active_lines,                    self.namespace.ignore_comments,                    self.namespace.ignore_docstrings,                    self.namespace.ignore_imports,                    self.namespace.ignore_signatures,                )            )            lines = readlines()         except UnicodeDecodeError:            pass            lines = []        self.linesets.append(            LineSet(                streamid,                lines,                self.namespace.ignore_comments,                self.namespace.ignore_docstrings,                self.namespace.ignore_imports,                self.namespace.ignore_signatures,                line_enabled_callback=self.linter._is_one_message_enabled  # type: ignore[attr-defined]                if hasattr(self, "linter")                else None,            )        )      def run(self) -> None:         """Start looking for similarities and display results on stdout."""


ignore_docstrings: bool,     ignore_imports: bool,     ignore_signatures: bool,<ins>    line_enabled_callback: Callable[[str, int], bool] | None = None,</ins> ) -> list[LineSpecifs]:     """Return tuples of line/line number/line type with leading/trailing whitespace and any ignored code features removed.


:param ignore_docstrings: if true, any line that is a docstring is removed from the result     :param ignore_imports: if true, any line that is an import is removed from the result     :param ignore_signatures: if true, any line that is part of a function signature is removed from the result<ins>    :param line_enabled_callback: If called with "R0801" and a line number, a return value of False will disregard the line</ins>     :return: the collection of line/line number/line type tuples     """     if ignore_imports or ignore_signatures:


strippedlines = []     docstring = None     for lineno, line in enumerate(lines, start=1):<ins>        if line_enabled_callback is not None and not line_enabled_callback(            "R0801", lineno        ):            continue</ins>         line = line.strip()         if ignore_docstrings:             if not docstring:


ignore_docstrings: bool = False,         ignore_imports: bool = False,         ignore_signatures: bool = False,        line_enabled_callback: Callable[[str, int], bool] | None = None,     ) -> None:         self.name = name         self._real_lines = lines         self._stripped_lines = stripped_lines(            lines, ignore_comments, ignore_docstrings, ignore_imports, ignore_signatures            lines,            ignore_comments,            ignore_docstrings,            ignore_imports,            ignore_signatures,            line_enabled_callback=line_enabled_callback,         )      def __str__(self):


from __future__ import annotations <ins>import argparse</ins> import copy import functools import itertools


from pylint.checkers import BaseChecker, MapReduceMixin, table_lines_from_stats from pylint.interfaces import IRawChecker from pylint.reporters.ureports.nodes import Tablefrom pylint.typing import OptionDict, Optionsfrom pylint.typing import Options from pylint.utils import LinterStats, decoding_stream  if TYPE_CHECKING:


ignore_imports: bool = False,         ignore_signatures: bool = False,     ) -> None:        self.min_lines = min_lines        self.ignore_comments = ignore_comments        self.ignore_docstrings = ignore_docstrings        self.ignore_imports = ignore_imports        self.ignore_signatures = ignore_signatures        # If we run in pylint mode we link the namespace objects        if isinstance(self, BaseChecker):            self.namespace = self.linter.config        else:            self.namespace = argparse.Namespace()        self.namespace.min_similarity_lines = min_lines        self.namespace.ignore_comments = ignore_comments        self.namespace.ignore_docstrings = ignore_docstrings        self.namespace.ignore_imports = ignore_imports        self.namespace.ignore_signatures = ignore_signatures         self.linesets: list[LineSet] = []      def append_stream(


LineSet(                     streamid,                     active_lines,                    self.ignore_comments,                    self.ignore_docstrings,                    self.ignore_imports,                    self.ignore_signatures,                    self.namespace.ignore_comments,                    self.namespace.ignore_docstrings,                    self.namespace.ignore_imports,                    self.namespace.ignore_signatures,                 )             )         except UnicodeDecodeError:


def run(self) -> None:         """Start looking for similarities and display results on stdout."""        if self.min_lines == 0:        if self.namespace.min_similarity_lines == 0:             return         self._display_sims(self._compute_sims())


hash_to_index_2: HashToIndex_T         index_to_lines_1: IndexToLines_T         index_to_lines_2: IndexToLines_T        hash_to_index_1, index_to_lines_1 = hash_lineset(lineset1, self.min_lines)        hash_to_index_2, index_to_lines_2 = hash_lineset(lineset2, self.min_lines)        hash_to_index_1, index_to_lines_1 = hash_lineset(            lineset1, self.namespace.min_similarity_lines        )        hash_to_index_2, index_to_lines_2 = hash_lineset(            lineset2, self.namespace.min_similarity_lines        )          hash_1: frozenset[LinesChunk] = frozenset(hash_to_index_1.keys())         hash_2: frozenset[LinesChunk] = frozenset(hash_to_index_2.keys())


] = CplSuccessiveLinesLimits(                     copy.copy(index_to_lines_1[index_1]),                     copy.copy(index_to_lines_2[index_2]),                    effective_cmn_lines_nb=self.min_lines,                    effective_cmn_lines_nb=self.namespace.min_similarity_lines,                 )          remove_successives(all_couples)


lineset1, start_index_1, lineset2, start_index_2, nb_common_lines             )             if eff_cmn_nb > self.min_lines:            if eff_cmn_nb > self.namespace.min_similarity_lines:                 yield com      def _iter_sims(self) -> Generator[Commonality, None, None]:


# reports     reports = (("RP0801", "Duplication", report_similarities),)     def __init__(self, linter=None) -> None:    def __init__(self, linter: PyLinter) -> None:         BaseChecker.__init__(self, linter)         Similar.__init__(             self,