Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

BUG: fix tab completion #37173

Merged
merged 4 commits into from
Oct 26, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions doc/source/whatsnew/v1.2.0.rst
Expand Up @@ -492,6 +492,7 @@ Other
- Fixed metadata propagation in the :class:`Series.dt` and :class:`Series.str` accessors (:issue:`28283`)
- Bug in :meth:`Index.union` behaving differently depending on whether operand is a :class:`Index` or other list-like (:issue:`36384`)
- Passing an array with 2 or more dimensions to the :class:`Series` constructor now raises the more specific ``ValueError``, from a bare ``Exception`` previously (:issue:`35744`)
- Bug in ``accessor.DirNamesMixin``, where ``dir(obj)`` wouldn't show attributes defined on the instance (:issue:`37173`).

.. ---------------------------------------------------------------------------

Expand Down
14 changes: 7 additions & 7 deletions pandas/core/accessor.py
Expand Up @@ -4,23 +4,23 @@
that can be mixed into or pinned onto other pandas classes.

"""
from typing import FrozenSet, Set
from typing import FrozenSet, List, Set
import warnings

from pandas.util._decorators import doc


class DirNamesMixin:
_accessors: Set[str] = set()
_deprecations: FrozenSet[str] = frozenset()
_hidden_attrs: FrozenSet[str] = frozenset()

def _dir_deletions(self):
def _dir_deletions(self) -> Set[str]:
"""
Delete unwanted __dir__ for this object.
"""
return self._accessors | self._deprecations
return self._accessors | self._hidden_attrs

def _dir_additions(self):
def _dir_additions(self) -> Set[str]:
"""
Add additional __dir__ for this object.
"""
Expand All @@ -33,15 +33,15 @@ def _dir_additions(self):
pass
return rv

def __dir__(self):
def __dir__(self) -> List[str]:
"""
Provide method name lookup and completion.

Notes
-----
Only provide 'public' methods.
"""
rv = set(dir(type(self)))
rv = set(super().__dir__())
rv = (rv - self._dir_deletions()) | self._dir_additions()
return sorted(rv)

Expand Down
2 changes: 1 addition & 1 deletion pandas/core/arrays/categorical.py
Expand Up @@ -288,7 +288,7 @@ class Categorical(NDArrayBackedExtensionArray, PandasObject, ObjectStringArrayMi
__array_priority__ = 1000
_dtype = CategoricalDtype(ordered=False)
# tolist is not actually deprecated, just suppressed in the __dir__
_deprecations = PandasObject._deprecations | frozenset(["tolist"])
_hidden_attrs = PandasObject._hidden_attrs | frozenset(["tolist"])
_typ = "categorical"
_can_hold_na = True

Expand Down
2 changes: 1 addition & 1 deletion pandas/core/arrays/sparse/array.py
Expand Up @@ -270,7 +270,7 @@ class SparseArray(OpsMixin, PandasObject, ExtensionArray):
"""

_subtyp = "sparse_array" # register ABCSparseArray
_deprecations = PandasObject._deprecations | frozenset(["get_values"])
_hidden_attrs = PandasObject._hidden_attrs | frozenset(["get_values"])
_sparse_index: SparseIndex

def __init__(
Expand Down
2 changes: 1 addition & 1 deletion pandas/core/base.py
Expand Up @@ -314,7 +314,7 @@ class IndexOpsMixin(OpsMixin):

# ndarray compatibility
__array_priority__ = 1000
_deprecations: FrozenSet[str] = frozenset(
_hidden_attrs: FrozenSet[str] = frozenset(
["tolist"] # tolist is not deprecated, just suppressed in the __dir__
)

Expand Down
2 changes: 1 addition & 1 deletion pandas/core/frame.py
Expand Up @@ -420,7 +420,7 @@ def _constructor(self) -> Type[DataFrame]:
return DataFrame

_constructor_sliced: Type[Series] = Series
_deprecations: FrozenSet[str] = NDFrame._deprecations | frozenset([])
_hidden_attrs: FrozenSet[str] = NDFrame._hidden_attrs | frozenset([])
_accessors: Set[str] = {"sparse"}

@property
Expand Down
2 changes: 1 addition & 1 deletion pandas/core/generic.py
Expand Up @@ -197,7 +197,7 @@ class NDFrame(PandasObject, SelectionMixin, indexing.IndexingMixin):
]
_internal_names_set: Set[str] = set(_internal_names)
_accessors: Set[str] = set()
_deprecations: FrozenSet[str] = frozenset(["get_values", "tshift"])
_hidden_attrs: FrozenSet[str] = frozenset(["get_values", "tshift"])
_metadata: List[str] = []
_is_copy = None
_mgr: BlockManager
Expand Down
15 changes: 15 additions & 0 deletions pandas/core/groupby/groupby.py
Expand Up @@ -489,6 +489,21 @@ def group_selection_context(groupby: "BaseGroupBy") -> Iterator["BaseGroupBy"]:
class BaseGroupBy(PandasObject, SelectionMixin, Generic[FrameOrSeries]):
_group_selection: Optional[IndexLabel] = None
_apply_allowlist: FrozenSet[str] = frozenset()
_hidden_attrs = PandasObject._hidden_attrs | {
"as_index",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah can you differentiate between deprecations that we are hiding and attributes that we are hing for another reason (e.g. these are private)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There may be deprecated attributes, that should not be hidden and vica versa. Also the deprecation log is in #30228, if we want to list deprecated attributes.

IMO it's ok to keep the concepts of hidden and deprecated attributes seperate.

"axis",
"dropna",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we want these to be hidden? Okay with keeping the same behavior as master in this PR, but maybe an issue should be opened.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good question. From a user perspective, I think it's ok to hide them (helps users focus on groupby methods), but I also think there are situation where we want them to be visible (when developing, advanced use cases).

Maybe store them as not-hidden internal attributes (_as_index etc)?

"exclusions",
"grouper",
"group_keys",
"keys",
"level",
jreback marked this conversation as resolved.
Show resolved Hide resolved
"mutated",
"obj",
"observed",
"sort",
"squeeze",
}

def __init__(
self,
Expand Down
5 changes: 5 additions & 0 deletions pandas/core/indexes/accessors.py
Expand Up @@ -28,6 +28,11 @@


class Properties(PandasDelegate, PandasObject, NoNewAttributesMixin):
_hidden_attrs = PandasObject._hidden_attrs | {
"orig",
"name",
}

def __init__(self, data: "Series", orig):
if not isinstance(data, ABCSeries):
raise TypeError(
Expand Down
6 changes: 3 additions & 3 deletions pandas/core/indexes/base.py
Expand Up @@ -193,9 +193,9 @@ class Index(IndexOpsMixin, PandasObject):
"""

# tolist is not actually deprecated, just suppressed in the __dir__
_deprecations: FrozenSet[str] = (
PandasObject._deprecations
| IndexOpsMixin._deprecations
_hidden_attrs: FrozenSet[str] = (
PandasObject._hidden_attrs
| IndexOpsMixin._hidden_attrs
| frozenset(["contains", "set_value"])
)

Expand Down
2 changes: 1 addition & 1 deletion pandas/core/indexes/multi.py
Expand Up @@ -258,7 +258,7 @@ class MultiIndex(Index):
of the mentioned helper methods.
"""

_deprecations = Index._deprecations | frozenset()
_hidden_attrs = Index._hidden_attrs | frozenset()

# initialize to zero-length tuples to make everything work
_typ = "multiindex"
Expand Down
6 changes: 3 additions & 3 deletions pandas/core/series.py
Expand Up @@ -181,9 +181,9 @@ class Series(base.IndexOpsMixin, generic.NDFrame):
_metadata: List[str] = ["name"]
_internal_names_set = {"index"} | generic.NDFrame._internal_names_set
_accessors = {"dt", "cat", "str", "sparse"}
_deprecations = (
base.IndexOpsMixin._deprecations
| generic.NDFrame._deprecations
_hidden_attrs = (
base.IndexOpsMixin._hidden_attrs
| generic.NDFrame._hidden_attrs
| frozenset(["compress", "ptp"])
)

Expand Down
16 changes: 16 additions & 0 deletions pandas/tests/test_register_accessor.py
Expand Up @@ -4,6 +4,22 @@

import pandas as pd
import pandas._testing as tm
from pandas.core import accessor


def test_dirname_mixin():
# GH37173

class X(accessor.DirNamesMixin):
x = 1
y: int

def __init__(self):
self.z = 3

result = [attr_name for attr_name in dir(X()) if not attr_name.startswith("_")]

assert result == ["x", "z"]


@contextlib.contextmanager
Expand Down