Skip to content

Commit

Permalink
chore: prepare 4.0.0b4 (falconry#2369)
Browse files Browse the repository at this point in the history
* chore: prepare `4.0.0b4`

* docs(changes): misc wording tweak

* docs: remove the note that the converted object is using UTC (it can be another tz)
  • Loading branch information
vytas7 authored Oct 14, 2024
1 parent 872a45e commit 9debc9e
Show file tree
Hide file tree
Showing 7 changed files with 69 additions and 19 deletions.
14 changes: 10 additions & 4 deletions docs/changes/4.0.0.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@ Changelog for Falcon 4.0.0
Summary
-------

The third beta release of Falcon 4.0.0 is here!
Falcon ``4.0.0b4`` is hopefully the final beta release before moving forward to
a release candidate.

Falcon 4.0 is now feature-complete, and we would really be thankful if you
As Falcon 4.0 is now feature-complete, we would really be thankful if you
could test this beta release with your apps, and
:ref:`let us know if you run into any issues <chat>`!
Please also check the list of **breaking changes** below.
Expand All @@ -16,9 +17,9 @@ checker of choice without any *typeshed* extensions for Falcon, and
:ref:`report back to us <chat>` how it went!

As always, you can grab the new release
`from PyPI <https://pypi.org/project/falcon/4.0.0b3/>`__::
`from PyPI <https://pypi.org/project/falcon/4.0.0b4/>`__::

pip install falcon==4.0.0b3
pip install falcon==4.0.0b4

(Alternatively, continue reading these docs for more
:ref:`installation options <install>`.)
Expand Down Expand Up @@ -232,6 +233,11 @@ Breaking Changes
:attr:`~falcon.Request.if_modified_since`,
:attr:`~falcon.Request.if_unmodified_since`, and
:attr:`falcon.testing.Cookie.expires`) has also changed to timezone-aware.

Furthermore, the default value of the `format_string` parameter in
:meth:`falcon.Request.get_param_as_datetime` and
:class:`falcon.routing.DateTimeConverter` has also been updated to use a
timezone-aware form.
(`#2182 <https://github.com/falconry/falcon/issues/2182>`__)
- ``setup.cfg`` was dropped in favor of consolidating all static project
configuration in ``pyproject.toml`` (``setup.py`` is still needed for
Expand Down
12 changes: 10 additions & 2 deletions falcon/request.py
Original file line number Diff line number Diff line change
Expand Up @@ -2134,7 +2134,7 @@ def get_param_as_datetime(
def get_param_as_datetime(
self,
name: str,
format_string: str = '%Y-%m-%dT%H:%M:%SZ',
format_string: str = '%Y-%m-%dT%H:%M:%S%z',
required: bool = False,
store: StoreArg = None,
default: Optional[datetime] = None,
Expand All @@ -2147,7 +2147,7 @@ def get_param_as_datetime(
Keyword Args:
format_string (str): String used to parse the param value
into a ``datetime``. Any format recognized by strptime() is
supported (default ``'%Y-%m-%dT%H:%M:%SZ'``).
supported (default ``'%Y-%m-%dT%H:%M:%S%z'``).
required (bool): Set to ``True`` to raise
``HTTPBadRequest`` instead of returning ``None`` when the
parameter is not found (default ``False``).
Expand All @@ -2165,6 +2165,14 @@ def get_param_as_datetime(
Raises:
HTTPBadRequest: A required param is missing from the request, or
the value could not be converted to a ``datetime``.
.. versionchanged:: 4.0
The default value of `format_string` was changed from
``'%Y-%m-%dT%H:%M:%SZ'`` to ``'%Y-%m-%dT%H:%M:%S%z'``.
The new format is a superset of the old one parsing-wise, however,
the converted :class:`~datetime.datetime` object is now
timezone-aware.
"""

param_value = self.get_param(name, required=required)
Expand Down
11 changes: 9 additions & 2 deletions falcon/routing/converters.py
Original file line number Diff line number Diff line change
Expand Up @@ -182,12 +182,19 @@ class DateTimeConverter(BaseConverter):
Keyword Args:
format_string (str): String used to parse the field value
into a datetime. Any format recognized by strptime() is
supported (default ``'%Y-%m-%dT%H:%M:%SZ'``).
supported (default ``'%Y-%m-%dT%H:%M:%S%z'``).
.. versionchanged:: 4.0
The default value of `format_string` was changed from
``'%Y-%m-%dT%H:%M:%SZ'`` to ``'%Y-%m-%dT%H:%M:%S%z'``.
The new format is a superset of the old one parsing-wise, however, the
converted :class:`~datetime.datetime` object is now timezone-aware.
"""

__slots__ = ('_format_string',)

def __init__(self, format_string: str = '%Y-%m-%dT%H:%M:%SZ') -> None:
def __init__(self, format_string: str = '%Y-%m-%dT%H:%M:%S%z') -> None:
self._format_string = format_string

def convert(self, value: str) -> Optional[datetime]:
Expand Down
2 changes: 1 addition & 1 deletion falcon/version.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,5 @@

"""Falcon version."""

__version__ = '4.0.0b3'
__version__ = '4.0.0b4'
"""Current version of Falcon."""
41 changes: 33 additions & 8 deletions tests/test_query_params.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from datetime import date
from datetime import datetime
from datetime import timezone
import json
from uuid import UUID

Expand Down Expand Up @@ -848,7 +849,9 @@ def test_get_datetime_valid(self, simulate_request, client, resource):
query_string = 'thedate={}'.format(date_value)
simulate_request(client=client, path='/', query_string=query_string)
req = resource.captured_req
assert req.get_param_as_datetime('thedate') == datetime(2015, 4, 20, 10, 10, 10)
assert req.get_param_as_datetime('thedate') == datetime(
2015, 4, 20, 10, 10, 10, tzinfo=timezone.utc
)

def test_get_datetime_missing_param(self, simulate_request, client, resource):
client.app.add_route('/', resource)
Expand All @@ -857,16 +860,36 @@ def test_get_datetime_missing_param(self, simulate_request, client, resource):
req = resource.captured_req
assert req.get_param_as_datetime('thedate') is None

def test_get_datetime_valid_with_format(self, simulate_request, client, resource):
@pytest.mark.parametrize(
'format_string, date_value, expected',
[
('%Y%m%d %H:%M:%S', '20150420 10:10:10', datetime(2015, 4, 20, 10, 10, 10)),
(
'%Y-%m-%dT%H:%M:%SZ',
'2015-04-20T10:10:10Z',
datetime(2015, 4, 20, 10, 10, 10),
),
(
'%Y%m%dT%H:%M:%S.%fZ',
'20150420T10:10:10.133701Z',
datetime(2015, 4, 20, 10, 10, 10, 133701),
),
],
)
def test_get_datetime_valid_with_format(
self, simulate_request, client, resource, format_string, date_value, expected
):
client.app.add_route('/', resource)
date_value = '20150420 10:10:10'
query_string = 'thedate={}'.format(date_value)
format_string = '%Y%m%d %H:%M:%S'
simulate_request(client=client, path='/', query_string=query_string)
req = resource.captured_req
assert req.get_param_as_datetime(
'thedate', format_string=format_string
) == datetime(2015, 4, 20, 10, 10, 10)
assert (
req.get_param_as_datetime(
'thedate',
format_string=format_string,
)
== expected
)

def test_get_datetime_store(self, simulate_request, client, resource):
client.app.add_route('/', resource)
Expand All @@ -877,7 +900,9 @@ def test_get_datetime_store(self, simulate_request, client, resource):
store = {}
req.get_param_as_datetime('thedate', store=store)
assert len(store) != 0
assert store.get('thedate') == datetime(2015, 4, 20, 10, 10, 10)
assert store.get('thedate') == datetime(
2015, 4, 20, 10, 10, 10, tzinfo=timezone.utc
)

def test_get_datetime_invalid(self, simulate_request, client, resource):
client.app.add_route('/', resource)
Expand Down
5 changes: 4 additions & 1 deletion tests/test_uri_converters.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from datetime import datetime
from datetime import timezone
import math
import string
import uuid
Expand Down Expand Up @@ -153,7 +154,9 @@ def test_datetime_converter(value, format_string, expected):

def test_datetime_converter_default_format():
c = converters.DateTimeConverter()
assert c.convert('2017-07-03T14:30:01Z') == datetime(2017, 7, 3, 14, 30, 1)
assert c.convert('2017-07-03T14:30:01Z') == datetime(
2017, 7, 3, 14, 30, 1, tzinfo=timezone.utc
)


@pytest.mark.parametrize(
Expand Down
3 changes: 2 additions & 1 deletion tests/test_uri_templates.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
"""

from datetime import datetime
from datetime import timezone
import math
import uuid

Expand Down Expand Up @@ -288,7 +289,7 @@ def test_int_converter_rejections(client, uri_template):
(
'/{start_year:int}-to-{timestamp:dt}',
'/1961-to-1969-07-21T02:56:00Z',
datetime(1969, 7, 21, 2, 56, 0),
datetime(1969, 7, 21, 2, 56, 0, tzinfo=timezone.utc),
),
(
'/{start_year:int}-to-{timestamp:dt("%Y-%m-%d")}',
Expand Down

0 comments on commit 9debc9e

Please sign in to comment.