diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 155b2227..af2bdf9e 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -44,6 +44,10 @@ jobs: with: path: .venv key: venv-${{ runner.os }}-${{ steps.full-python-version.outputs.version }}-${{ hashFiles('**/poetry.lock') }} + - name: Upgrade pip + run: | + source $HOME/.poetry/env + poetry run python -m pip install pip -U - name: Install dependencies run: | source $HOME/.poetry/env @@ -86,6 +90,10 @@ jobs: with: path: .venv key: venv-${{ runner.os }}-${{ steps.full-python-version.outputs.version }}-fix-${{ hashFiles('**/poetry.lock') }} + - name: Upgrade pip + run: | + source $HOME/.poetry/env + poetry run python -m pip install pip -U - name: Install dependencies run: | source $HOME/.poetry/env @@ -127,6 +135,10 @@ jobs: with: path: .venv key: venv-${{ runner.os }}-${{ steps.full-python-version.outputs.version }}-${{ hashFiles('**/poetry.lock') }} + - name: Upgrade pip + run: | + $env:Path += ";$env:Userprofile\.poetry\bin" + poetry run python -m pip install pip -U - name: Install dependencies run: | $env:Path += ";$env:Userprofile\.poetry\bin" diff --git a/pendulum/__init__.py b/pendulum/__init__.py index 78524b2c..bb1e0ca7 100644 --- a/pendulum/__init__.py +++ b/pendulum/__init__.py @@ -216,7 +216,17 @@ def now(tz=None): # type: (Optional[Union[str, _Timezone]]) -> DateTime tz = _safe_timezone(tz) dt = tz.convert(dt) - return instance(dt, tz) + return DateTime( + dt.year, + dt.month, + dt.day, + dt.hour, + dt.minute, + dt.second, + dt.microsecond, + tzinfo=dt.tzinfo, + fold=dt.fold if _HAS_FOLD else 0, + ) def today(tz="local"): # type: (Union[str, _Timezone]) -> DateTime diff --git a/poetry.lock b/poetry.lock index 0c58f9fc..4b5211bb 100644 --- a/poetry.lock +++ b/poetry.lock @@ -99,10 +99,10 @@ description = "Cleo allows you to create beautiful and testable command-line int name = "cleo" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -version = "0.7.6" +version = "0.8.1" [package.dependencies] -clikit = ">=0.4.0,<0.5.0" +clikit = ">=0.6.0,<0.7.0" [[package]] category = "dev" @@ -118,14 +118,15 @@ description = "CliKit is a group of utilities to build beautiful and testable co name = "clikit" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -version = "0.4.3" +version = "0.6.2" [package.dependencies] pastel = ">=0.2.0,<0.3.0" pylev = ">=1.3,<2.0" +crashtest = {version = ">=0.3.0,<0.4.0", markers = "python_version >= \"3.6\" and python_version < \"4.0\""} enum34 = {version = ">=1.1,<2.0", markers = "python_version >= \"2.7\" and python_version < \"2.8\""} typing = {version = ">=3.6,<4.0", markers = "python_version >= \"2.7\" and python_version < \"2.8\" or python_version >= \"3.4\" and python_version < \"3.5\""} -typing-extensions = {version = ">=3.6,<4.0", markers = "python_version >= \"3.5.0\" and python_version < \"3.5.4\""} +typing-extensions = {version = ">=3.6,<4.0", markers = "python_version >= \"3.5\" and python_full_version < \"3.5.4\""} [[package]] category = "dev" @@ -166,6 +167,14 @@ version = "5.1" [package.extras] toml = ["toml"] +[[package]] +category = "dev" +description = "Manage Python errors with ease" +name = "crashtest" +optional = false +python-versions = ">=3.6,<4.0" +version = "0.3.0" + [[package]] category = "dev" description = "Distribution utilities" @@ -190,6 +199,18 @@ optional = false python-versions = "*" version = "3.0.12" +[[package]] +category = "dev" +description = "Let your Python tests travel through time" +name = "freezegun" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +version = "0.3.15" + +[package.dependencies] +python-dateutil = ">=1.0,<2.0 || >2.0" +six = "*" + [[package]] category = "dev" description = "Python function signatures from PEP362 for Python 2.6, 2.7 and 3.2+" @@ -713,7 +734,7 @@ docs = ["sphinx", "jaraco.packaging (>=3.2)", "rst.linker (>=1.9)"] testing = ["pathlib2", "unittest2", "jaraco.itertools", "func-timeout"] [metadata] -content-hash = "0f423ffa1c413a3d812c9af00057382655b1f4527551359f5270d6c742ee83fb" +content-hash = "531d174befc626d82bcaabeccd06cfeff9f4e81201993bdd9b61cd5f50e54123" python-versions = "~2.7 || ^3.5" [metadata.files] @@ -750,16 +771,16 @@ cfgv = [ {file = "cfgv-2.0.1.tar.gz", hash = "sha256:edb387943b665bf9c434f717bf630fa78aecd53d5900d2e05da6ad6048553144"}, ] cleo = [ - {file = "cleo-0.7.6-py2.py3-none-any.whl", hash = "sha256:9443d67e5b2da79b32d820ae41758dd6a25618345cb10b9a022a695e26b291b9"}, - {file = "cleo-0.7.6.tar.gz", hash = "sha256:99cf342406f3499cec43270fcfaf93c126c5164092eca201dfef0f623360b409"}, + {file = "cleo-0.8.1-py2.py3-none-any.whl", hash = "sha256:141cda6dc94a92343be626bb87a0b6c86ae291dfc732a57bf04310d4b4201753"}, + {file = "cleo-0.8.1.tar.gz", hash = "sha256:3d0e22d30117851b45970b6c14aca4ab0b18b1b53c8af57bed13208147e4069f"}, ] click = [ {file = "click-7.1.2-py2.py3-none-any.whl", hash = "sha256:dacca89f4bfadd5de3d7489b7c8a566eee0d3676333fbb50030263894c38c0dc"}, {file = "click-7.1.2.tar.gz", hash = "sha256:d2b5255c7c6349bc1bd1e59e08cd12acbbd63ce649f2588755783aa94dfb6b1a"}, ] clikit = [ - {file = "clikit-0.4.3-py2.py3-none-any.whl", hash = "sha256:71e321b7795a2a6c4888629f43365d52db071737e668ab16861121d7dd3ada09"}, - {file = "clikit-0.4.3.tar.gz", hash = "sha256:6e2d7e115e7c7b35bceb0209109935ab2f9ab50910e9ff2293f7fa0b7abf973e"}, + {file = "clikit-0.6.2-py2.py3-none-any.whl", hash = "sha256:71268e074e68082306e23d7369a7b99f824a0ef926e55ba2665e911f7208489e"}, + {file = "clikit-0.6.2.tar.gz", hash = "sha256:442ee5db9a14120635c5990bcdbfe7c03ada5898291f0c802f77be71569ded59"}, ] colorama = [ {file = "colorama-0.4.3-py2.py3-none-any.whl", hash = "sha256:7d73d2a99753107a36ac6b455ee49046802e59d9d076ef8e47b61499fa29afff"}, @@ -806,6 +827,10 @@ coverage = [ {file = "coverage-5.1-cp39-cp39-win_amd64.whl", hash = "sha256:bb28a7245de68bf29f6fb199545d072d1036a1917dca17a1e75bbb919e14ee8e"}, {file = "coverage-5.1.tar.gz", hash = "sha256:f90bfc4ad18450c80b024036eaf91e4a246ae287701aaa88eaebebf150868052"}, ] +crashtest = [ + {file = "crashtest-0.3.0-py3-none-any.whl", hash = "sha256:06069a9267c54be31c42b03574b72407bf780e13c82cb0238f24ea69cf25b6dd"}, + {file = "crashtest-0.3.0.tar.gz", hash = "sha256:e9c06cc96400939ab5327123a3f699078eaad8a6283247d7b2ae0f6afffadf14"}, +] distlib = [ {file = "distlib-0.3.1-py2.py3-none-any.whl", hash = "sha256:8c09de2c67b3e7deef7184574fc060ab8a793e7adbb183d942c389c8b13c52fb"}, {file = "distlib-0.3.1.zip", hash = "sha256:edf6116872c863e1aa9d5bb7cb5e05a022c519a4594dc703843343a9ddd9bff1"}, @@ -819,6 +844,10 @@ filelock = [ {file = "filelock-3.0.12-py3-none-any.whl", hash = "sha256:929b7d63ec5b7d6b71b0fa5ac14e030b3f70b75747cef1b10da9b879fef15836"}, {file = "filelock-3.0.12.tar.gz", hash = "sha256:18d82244ee114f543149c66a6e0c14e9c4f8a1044b5cdaadd0f82159d6a6ff59"}, ] +freezegun = [ + {file = "freezegun-0.3.15-py2.py3-none-any.whl", hash = "sha256:82c757a05b7c7ca3e176bfebd7d6779fd9139c7cb4ef969c38a28d74deef89b2"}, + {file = "freezegun-0.3.15.tar.gz", hash = "sha256:e2062f2c7f95cc276a834c22f1a17179467176b624cc6f936e8bc3be5535ad1b"}, +] funcsigs = [ {file = "funcsigs-1.0.2-py2.py3-none-any.whl", hash = "sha256:330cc27ccbf7f1e992e69fef78261dc7c6569012cf397db8d3de0234e6c937ca"}, {file = "funcsigs-1.0.2.tar.gz", hash = "sha256:a7bb0f2cf3a3fd1ab2732cb49eba4252c2af4240442415b4abce3b87022a8f50"}, diff --git a/pyproject.toml b/pyproject.toml index 95082049..0aecf2d5 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -32,7 +32,7 @@ pytest = "^4.6" pytest-cov = "^2.5" pytz = ">=2018.3" babel = "^2.5" -cleo = "^0.7.5" +cleo = "^0.8.1" tox = "^3.0" black = { version = "^19.3b0", markers = "python_version >= '3.6' and python_version < '4.0' and implementation_name != 'pypy'" } isort = { version = "^4.3.21", markers = "python_version >= '3.6' and python_version < '4.0'" } @@ -41,6 +41,7 @@ mkdocs = { version = "^1.0", python = "^3.5" } pymdown-extensions = "^6.0" pygments = "^2.2" markdown-include = "^0.5.1" +freezegun = "^0.3.15" [tool.isort] @@ -62,6 +63,7 @@ known_third_party = [ "babel", "cleo", "dateutil", + "freezegun", "pytzdata", ] diff --git a/tests/datetime/test_construct.py b/tests/datetime/test_construct.py index b5db944c..2e45ead9 100644 --- a/tests/datetime/test_construct.py +++ b/tests/datetime/test_construct.py @@ -3,6 +3,7 @@ from datetime import datetime from dateutil import tz +from freezegun import freeze_time import pendulum import pytest @@ -10,6 +11,7 @@ from pendulum import DateTime from pendulum.tz import timezone +from pendulum.utils._compat import PY36 from ..conftest import assert_datetime @@ -102,6 +104,50 @@ def test_now(): assert now.hour != in_paris.hour +@pytest.mark.skipif(not PY36, reason="fold attribute only present in Python 3.6+") +@freeze_time("2016-03-27 00:30:00") +def test_now_dst_off(): + utc = pendulum.now("UTC") + in_paris = pendulum.now("Europe/Paris") + in_paris_from_utc = utc.in_tz("Europe/Paris") + assert in_paris.hour == 1 + assert not in_paris.is_dst() + assert in_paris.isoformat() == in_paris_from_utc.isoformat() + + +@pytest.mark.skipif(not PY36, reason="fold attribute only present in Python 3.6+") +@freeze_time("2016-03-27 01:30:00") +def test_now_dst_transitioning_on(): + utc = pendulum.now("UTC") + in_paris = pendulum.now("Europe/Paris") + in_paris_from_utc = utc.in_tz("Europe/Paris") + assert in_paris.hour == 3 + assert in_paris.is_dst() + assert in_paris.isoformat() == in_paris_from_utc.isoformat() + + +@pytest.mark.skipif(not PY36, reason="fold attribute only present in Python 3.6+") +@freeze_time("2016-10-30 00:30:00") +def test_now_dst_on(): + utc = pendulum.now("UTC") + in_paris = pendulum.now("Europe/Paris") + in_paris_from_utc = utc.in_tz("Europe/Paris") + assert in_paris.hour == 2 + assert in_paris.is_dst() + assert in_paris.isoformat() == in_paris_from_utc.isoformat() + + +@pytest.mark.skipif(not PY36, reason="fold attribute only present in Python 3.6+") +@freeze_time("2016-10-30 01:30:00") +def test_now_dst_transitioning_off(): + utc = pendulum.now("UTC") + in_paris = pendulum.now("Europe/Paris") + in_paris_from_utc = utc.in_tz("Europe/Paris") + assert in_paris.hour == 2 + assert not in_paris.is_dst() + assert in_paris.isoformat() == in_paris_from_utc.isoformat() + + def test_now_with_fixed_offset(): now = pendulum.now(6)