Skip to content
Open
Show file tree
Hide file tree
Changes from all 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,
}
Loading