Skip to content
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Doc/c-api/set.rst
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ subtypes but not for instances of :class:`frozenset` or its subtypes.

Return ``1`` if found and removed, ``0`` if not found (no action taken), and ``-1`` if an
error is encountered. Does not raise :exc:`KeyError` for missing keys. Raise a
:exc:`TypeError` if the *key* is unhashable. Unlike the Python :meth:`~frozenset.discard`
:exc:`TypeError` if the *key* is unhashable. Unlike the Python :meth:`~set.discard`
method, this function does not automatically convert unhashable sets into
temporary frozensets. Raise :exc:`SystemError` if *set* is not an
instance of :class:`set` or its subtype.
Expand Down
1 change: 1 addition & 0 deletions Doc/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
'misc_news',
'pydoc_topics',
'pyspecific',
'set_frozenset_search',
'sphinx.ext.coverage',
'sphinx.ext.doctest',
'sphinx.ext.extlinks',
Expand Down
2 changes: 1 addition & 1 deletion Doc/library/collections.abc.rst
Original file line number Diff line number Diff line change
Expand Up @@ -380,7 +380,7 @@ classes supporting container APIs. For example, to write a class supporting
the full :class:`Set` API, it is only necessary to supply the three underlying
abstract methods: :meth:`~object.__contains__`, :meth:`~container.__iter__`, and
:meth:`~object.__len__`. The ABC supplies the remaining methods such as
:meth:`!__and__` and :meth:`~frozenset.isdisjoint`::
:meth:`!__and__` and :meth:`~set.isdisjoint`::
Copy link
Contributor

Choose a reason for hiding this comment

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

I think you can revert this, as well as other cases, that reference common methods for set and frozenset.


class ListBasedSet(collections.abc.Set):
''' Alternate set implementation favoring space over speed
Expand Down
15 changes: 8 additions & 7 deletions Doc/library/stdtypes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4737,9 +4737,10 @@ The constructors for both classes work the same:
Return a shallow copy of the set.


Note, the non-operator versions of :meth:`union`, :meth:`intersection`,
:meth:`difference`, :meth:`symmetric_difference`, :meth:`issubset`, and
:meth:`issuperset` methods will accept any iterable as an argument. In
Note, the non-operator versions of :meth:`~set.union`,
:meth:`~set.intersection`, :meth:`~set.difference`,
:meth:`~set.symmetric_difference`, :meth:`~set.issubset`, and
:meth:`~set.issuperset` methods will accept any iterable as an argument. In
contrast, their operator based counterparts require their arguments to be
sets. This precludes error-prone constructions like ``set('abc') & 'cbs'``
in favor of the more readable ``set('abc').intersection('cbs')``.
Expand Down Expand Up @@ -4815,10 +4816,10 @@ The constructors for both classes work the same:
Remove all elements from the set.


Note, the non-operator versions of the :meth:`update`,
:meth:`intersection_update`, :meth:`difference_update`, and
:meth:`symmetric_difference_update` methods will accept any iterable as an
argument.
Note, the non-operator versions of the :meth:`~set.update`,
:meth:`~set.intersection_update`, :meth:`~set.difference_update`, and
:meth:`~set.symmetric_difference_update` methods will accept any iterable as
an argument.

Note, the *elem* argument to the :meth:`~object.__contains__`,
:meth:`remove`, and
Expand Down
117 changes: 117 additions & 0 deletions Doc/tools/extensions/set_frozenset_search.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
"""Adjust set and frozenset methods in search index and general index."""

from sphinx import addnodes
from sphinx.domains.python import ObjectEntry

COMMON_METHODS = {
"isdisjoint",
"issubset",
"issuperset",
"union",
"intersection",
"difference",
"symmetric_difference",
"copy",
}

SET_ONLY_METHODS = {
"update",
"intersection_update",
"difference_update",
"symmetric_difference_update",
"add",
"remove",
"discard",
"pop",
"clear",
}


def adjust_set_frozenset_method_anchors(app, doctree):
"""
Change all frozenset.method references to be set.method instead
(old anchors are kept around so as not to break links)
"""
if app.env.path2doc(doctree['source']) != 'library/stdtypes':
return

# adjust anchors in the text, adding set-based anchors
for desc in doctree.traverse(addnodes.desc):
for sig in desc.traverse(addnodes.desc_signature):
if not sig.get('fullname', '').startswith('frozenset.'):
continue
name = sig['fullname'].rsplit('.', 1)[-1]
if name not in COMMON_METHODS and name not in SET_ONLY_METHODS:
continue

newname = f"set.{name}"
for target in ('names', 'ids'):
sig.get(target, []).insert(0, newname)
sig['fullname'] = newname
sig['class'] = "set"


def index_set_frozenset_methods(app, env):
"""
Adjust search results for the built-in `set` and `frozenset` types so that
mutation-oriented methods show up only under `set`, and other methods show
up under both `set` and `frozenset`.

Also adjust the entries in the general index.
"""
domain = env.domains.get("py")

# add set methods to search index and remove the frozenset-based search
# results for those methods that frozenset does not support
for name in COMMON_METHODS | SET_ONLY_METHODS:
oldname = f"frozenset.{name}"
if oldname in domain.objects:
newname = f"set.{name}"
getter = (
domain.objects.pop
if name in SET_ONLY_METHODS
else domain.objects.__getitem__
)
docname, objname, objtype, alias = getter(oldname)
domain.objects[newname] = ObjectEntry(
docname, newname, objtype, False
)

# add set methods to general index and remove the frozenset-based entries
# for those methods that frozenset does not support
stddata = env.domaindata.get('index', {}).get('entries', None)
if stddata is not None:
for docname, entries in list(stddata.items()):
new_entries = []
for entry in entries:
entrytype, entryname, target, ignored, key = entry
if (
target.startswith('frozenset.')
and '(frozenset method)' in entryname
):
method = target.removeprefix('frozenset.')
new_entries.append((
entrytype,
entryname.replace(
'(frozenset method)', '(set method)'
),
f"set.{method}",
ignored,
key,
))
if method not in SET_ONLY_METHODS:
new_entries.append(entry)
else:
new_entries.append(entry)

stddata[docname] = new_entries


def setup(app):
app.connect("doctree-read", adjust_set_frozenset_method_anchors)
app.connect("env-updated", index_set_frozenset_methods)
return {
"version": "1.0",
"parallel_read_safe": True,
"parallel_write_safe": True,
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Fixed incorrect/misleading search results related to :class:`set` and
:class:`frozenset` methods. Patch by Adam Hartz.
Loading