Compare commits

...

3 Commits

Author SHA1 Message Date
Miss Islington (bot) edf744990e
gh-99392: Fix sqlite3 converter recipes (GH-99393)
(cherry picked from commit dfc1b17a23)

Co-authored-by: naglis <827324+naglis@users.noreply.github.com>
2022-11-12 11:48:52 -08:00
Miss Islington (bot) 944ac46b88
[3.11] gh-99304: [Enum] clarify what constitutes a flag alias (GH-99395) (GH-99415)
gh-99304: [Enum] clarify what constitutes a flag alias (GH-99395)
(cherry picked from commit 73a921b070)

Co-authored-by: Ethan Furman <ethan@stoneleaf.us>
Co-authored-by: C.A.M. Gerlach <CAM.Gerlach@Gerlach.CAM>
2022-11-12 10:43:32 -08:00
Miss Islington (bot) ecc164f350
bpo-34272: Reorganize C API tests. (GH-8551)
Move some C API tests into Lib/test/test_capi/.
(cherry picked from commit f883b7f8ee)

Co-authored-by: Serhiy Storchaka <storchaka@gmail.com>
2022-11-12 09:36:42 -08:00
9 changed files with 104 additions and 18 deletions

View File

@ -173,6 +173,7 @@ yourself some work and use :func:`auto()` for the values::
... FRIDAY = auto()
... SATURDAY = auto()
... SUNDAY = auto()
... WEEKEND = SATURDAY | SUNDAY
.. _enum-advanced-tutorial:
@ -305,6 +306,10 @@ Iterating over the members of an enum does not provide the aliases::
>>> list(Shape)
[<Shape.SQUARE: 2>, <Shape.DIAMOND: 1>, <Shape.CIRCLE: 3>]
>>> list(Weekday)
[<Weekday.MONDAY: 1>, <Weekday.TUESDAY: 2>, <Weekday.WEDNESDAY: 4>, <Weekday.THURSDAY: 8>, <Weekday.FRIDAY: 16>, <Weekday.SATURDAY: 32>, <Weekday.SUNDAY: 64>]
Note that the aliases ``Shape.ALIAS_FOR_SQUARE`` and ``Weekday.WEEKEND`` aren't shown.
The special attribute ``__members__`` is a read-only ordered mapping of names
to members. It includes all names defined in the enumeration, including the
@ -324,6 +329,11 @@ the enumeration members. For example, finding all the aliases::
>>> [name for name, member in Shape.__members__.items() if member.name != name]
['ALIAS_FOR_SQUARE']
.. note::
Aliases for flags include values with multiple flags set, such as ``3``,
and no flags set, i.e. ``0``.
Comparisons
-----------
@ -751,7 +761,7 @@ flags being set, the boolean evaluation is :data:`False`::
False
Individual flags should have values that are powers of two (1, 2, 4, 8, ...),
while combinations of flags won't::
while combinations of flags will not::
>>> class Color(Flag):
... RED = auto()
@ -1107,8 +1117,8 @@ example of when ``KEEP`` is needed).
.. _enum-class-differences:
How are Enums different?
------------------------
How are Enums and Flags different?
----------------------------------
Enums have a custom metaclass that affects many aspects of both derived :class:`Enum`
classes and their instances (members).
@ -1125,6 +1135,13 @@ responsible for ensuring that various other methods on the final :class:`Enum`
class are correct (such as :meth:`__new__`, :meth:`__getnewargs__`,
:meth:`__str__` and :meth:`__repr__`).
Flag Classes
^^^^^^^^^^^^
Flags have an expanded view of aliasing: to be canonical, the value of a flag
needs to be a power-of-two value, and not a duplicate name. So, in addition to the
:class:`Enum` definition of alias, a flag with no value (a.k.a. ``0``) or with more than one
power-of-two value (e.g. ``3``) is considered an alias.
Enum Members (aka instances)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@ -1134,9 +1151,35 @@ The most interesting thing about enum members is that they are singletons.
and then puts a custom :meth:`__new__` in place to ensure that no new ones are
ever instantiated by returning only the existing member instances.
Flag Members
^^^^^^^^^^^^
Flag members can be iterated over just like the :class:`Flag` class, and only the
canonical members will be returned. For example::
>>> list(Color)
[<Color.RED: 1>, <Color.GREEN: 2>, <Color.BLUE: 4>]
(Note that ``BLACK``, ``PURPLE``, and ``WHITE`` do not show up.)
Inverting a flag member returns the corresponding positive value,
rather than a negative value --- for example::
>>> ~Color.RED
<Color.GREEN|BLUE: 6>
Flag members have a length corresponding to the number of power-of-two values
they contain. For example::
>>> len(Color.PURPLE)
2
.. _enum-cookbook:
Enum Cookbook
-------------
While :class:`Enum`, :class:`IntEnum`, :class:`StrEnum`, :class:`Flag`, and
:class:`IntFlag` are expected to cover the majority of use-cases, they cannot

View File

@ -27,7 +27,8 @@
An enumeration:
* is a set of symbolic names (members) bound to unique values
* can be iterated over to return its members in definition order
* can be iterated over to return its canonical (i.e. non-alias) members in
definition order
* uses *call* syntax to return members by value
* uses *index* syntax to return members by name
@ -432,19 +433,23 @@ Data Types
in most of the same places that a string can be used. The result of any string
operation performed on or with a *StrEnum* member is not part of the enumeration.
.. note:: There are places in the stdlib that check for an exact :class:`str`
instead of a :class:`str` subclass (i.e. ``type(unknown) == str``
instead of ``isinstance(unknown, str)``), and in those locations you
will need to use ``str(StrEnum.member)``.
.. note::
There are places in the stdlib that check for an exact :class:`str`
instead of a :class:`str` subclass (i.e. ``type(unknown) == str``
instead of ``isinstance(unknown, str)``), and in those locations you
will need to use ``str(StrEnum.member)``.
.. note::
Using :class:`auto` with :class:`StrEnum` results in the lower-cased member
name as the value.
.. note:: :meth:`__str__` is :func:`str.__str__` to better support the
*replacement of existing constants* use-case. :meth:`__format__` is likewise
:func:`str.__format__` for that same reason.
.. note::
:meth:`~object.__str__` is :meth:`!str.__str__` to better support the
*replacement of existing constants* use-case. :meth:`~object.__format__` is likewise
:meth:`!str.__format__` for that same reason.
.. versionadded:: 3.11
@ -476,13 +481,17 @@ Data Types
.. method:: __iter__(self):
Returns all contained members::
Returns all contained non-alias members::
>>> list(Color.RED)
[<Color.RED: 1>]
>>> list(purple)
[<Color.RED: 1>, <Color.BLUE: 4>]
.. versionchanged:: 3.11
Aliases are no longer returned during iteration.
.. method:: __len__(self):
Returns number of members in flag::
@ -592,9 +601,15 @@ Data Types
Using :class:`auto` with :class:`IntFlag` results in integers that are powers
of two, starting with ``1``.
.. versionchanged:: 3.11 :meth:`__str__` is now :func:`int.__str__` to
better support the *replacement of existing constants* use-case.
:meth:`__format__` was already :func:`int.__format__` for that same reason.
.. versionchanged:: 3.11
:meth:`~object.__str__` is now :meth:`!int.__str__` to better support the
*replacement of existing constants* use-case. :meth:`~object.__format__` was
already :meth:`!int.__format__` for that same reason.
Inversion of a :class:`!IntFlag` now returns a positive value that is the
union of all flags not in the given flag, rather than a negative value.
This matches the existing :class:`Flag` behavior.
.. class:: ReprEnum

View File

@ -2069,20 +2069,39 @@ This section shows recipes for common adapters and converters.
def convert_date(val):
"""Convert ISO 8601 date to datetime.date object."""
return datetime.date.fromisoformat(val)
return datetime.date.fromisoformat(val.decode())
def convert_datetime(val):
"""Convert ISO 8601 datetime to datetime.datetime object."""
return datetime.datetime.fromisoformat(val)
return datetime.datetime.fromisoformat(val.decode())
def convert_timestamp(val):
"""Convert Unix epoch timestamp to datetime.datetime object."""
return datetime.datetime.fromtimestamp(val)
return datetime.datetime.fromtimestamp(int(val))
sqlite3.register_converter("date", convert_date)
sqlite3.register_converter("datetime", convert_datetime)
sqlite3.register_converter("timestamp", convert_timestamp)
.. testcode::
:hide:
dt = datetime.datetime(2019, 5, 18, 15, 17, 8, 123456)
assert adapt_date_iso(dt.date()) == "2019-05-18"
assert convert_date(b"2019-05-18") == dt.date()
assert adapt_datetime_iso(dt) == "2019-05-18T15:17:08.123456"
assert convert_datetime(b"2019-05-18T15:17:08.123456") == dt
# Using current time as fromtimestamp() returns local date/time.
# Droping microseconds as adapt_datetime_epoch truncates fractional second part.
now = datetime.datetime.now().replace(microsecond=0)
current_timestamp = int(now.timestamp())
assert adapt_datetime_epoch(now) == current_timestamp
assert convert_timestamp(str(current_timestamp).encode()) == now
.. _sqlite3-connection-shortcuts:

View File

@ -0,0 +1,5 @@
import os
from test.support import load_package_tests
def load_tests(*args):
return load_package_tests(os.path.dirname(__file__), *args)

View File

@ -0,0 +1,3 @@
import unittest
unittest.main('test.test_capi')

View File

@ -0,0 +1 @@
Some C API tests were moved into the new Lib/test/test_capi/ directory.