mirror of
https://github.com/kennethreitz/pipenv.git
synced 2026-06-05 22:50:18 +00:00
Merge pull request #1982 from pypa/purge-rfc3339-timestamp
Purge strict-rfc3339 and timestamp from prettytoml
This commit is contained in:
@@ -13,6 +13,7 @@ pytest-tap = "*"
|
||||
flaky = "*"
|
||||
stdeb = {version="*", markers="sys_platform == 'linux'"}
|
||||
white = {version="*", markers="python_version >= '3.6'"}
|
||||
pytz = "*"
|
||||
|
||||
[packages]
|
||||
|
||||
|
||||
Generated
+12
-9
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"_meta": {
|
||||
"hash": {
|
||||
"sha256": "5941b36256503b9729e927f3249a366748da5c353b59c1e32ca7fd919b31a4d6"
|
||||
"sha256": "bc81bb0e64d7ed1eed2627819b4a806d8cba554c1e0398191ba1ba32a216ed2a"
|
||||
},
|
||||
"pipfile-spec": 6,
|
||||
"requires": {},
|
||||
@@ -277,10 +277,10 @@
|
||||
},
|
||||
"pbr": {
|
||||
"hashes": [
|
||||
"sha256:56b7a8ba7d64bf6135a9dfefb85a80d95924b3fde5ed6343a1a1d464a040dae3",
|
||||
"sha256:de75cf1d510542c746beeff66b52241eb12c8f95f2ef846ee50ed5d72392caa4"
|
||||
],
|
||||
"version": "==4.0.1"
|
||||
"sha256:4e8a0ed6a8705a26768f4c3da26026013b157821fe5f95881599556ea9d91c19",
|
||||
"sha256:dae4aaa78eafcad10ce2581fc34d694faa616727837fd8e55c1a00951ad6744f"
|
||||
],
|
||||
"version": "==4.0.2"
|
||||
},
|
||||
"pipenv": {
|
||||
"editable": true,
|
||||
@@ -295,6 +295,7 @@
|
||||
},
|
||||
"pluggy": {
|
||||
"hashes": [
|
||||
"sha256:714306e9b9a7b24ee4c1e3ff6463d7f652cdd30f4693121b31572e2fe1fdaea3",
|
||||
"sha256:d345c8fe681115900d6da8d048ba67c25df42973bda370783cd58826442dcd7c",
|
||||
"sha256:e160a7fcf25762bb60efc7e171d4497ff1d8d2d75a3d0df7a21b76821ecbf5c5",
|
||||
"sha256:7f8ae7f5bdf75671a718d2daf0a64b7885f74510bcd98b1a0bb420eb9a9d0cff"
|
||||
@@ -310,6 +311,8 @@
|
||||
},
|
||||
"pycodestyle": {
|
||||
"hashes": [
|
||||
"sha256:1ec08a51c901dfe44921576ed6e4c1f5b7ecbad403f871397feedb5eb8e4fa14",
|
||||
"sha256:5ff2fbcbab997895ba9ead77e1b38b3ebc2e5c3b8a6194ef918666e4c790a00e",
|
||||
"sha256:682256a5b318149ca0d2a9185d365d8864a768a28db66a84a2ea946bcc426766",
|
||||
"sha256:6c4245ade1edfad79c3446fadfc96b0de2759662dc29d07d80a6f27ad1ca6ba9"
|
||||
],
|
||||
@@ -452,10 +455,10 @@
|
||||
},
|
||||
"tqdm": {
|
||||
"hashes": [
|
||||
"sha256:4f2eb1d14804caf7095500fe11da0e481a47af912e7b57c93f886ac3c40a49dd",
|
||||
"sha256:91ac47ec2ba6bb92b7ba37706f4dea37019ddd784b22fd279a4b12d93327191d"
|
||||
],
|
||||
"version": "==4.20.0"
|
||||
"sha256:597e7526c85df881d51e094360181a84533aede1cb3f5a1cada8bbd4de557efd",
|
||||
"sha256:fe3d218d5b61993d415aa2a9db6dd64c0e4cefb90164ebb197ef3b1d99f531dc"
|
||||
],
|
||||
"version": "==4.23.0"
|
||||
},
|
||||
"twine": {
|
||||
"hashes": [
|
||||
|
||||
@@ -5,11 +5,8 @@ A converter of python values to TOML Token instances.
|
||||
import codecs
|
||||
import datetime
|
||||
import six
|
||||
import strict_rfc3339
|
||||
import timestamp
|
||||
from prettytoml import tokens
|
||||
import re
|
||||
from prettytoml.elements.metadata import NewlineElement
|
||||
from prettytoml.errors import TOMLError
|
||||
from prettytoml.tokens import Token
|
||||
from prettytoml.util import chunkate_string
|
||||
@@ -49,8 +46,10 @@ def create_primitive_token(value, multiline_strings_allowed=True):
|
||||
elif isinstance(value, float):
|
||||
return tokens.Token(tokens.TYPE_FLOAT, u'{}'.format(value))
|
||||
elif isinstance(value, (datetime.datetime, datetime.date, datetime.time)):
|
||||
ts = timestamp(value) // 1000
|
||||
return tokens.Token(tokens.TYPE_DATE, strict_rfc3339.timestamp_to_rfc3339_utcoffset(ts))
|
||||
s = value.isoformat()
|
||||
if s.endswith('+00:00'):
|
||||
s = s[:-6] + 'Z'
|
||||
return tokens.Token(tokens.TYPE_DATE, s)
|
||||
elif isinstance(value, six.string_types):
|
||||
return create_string_token(value, multiline_strings_allowed=multiline_strings_allowed)
|
||||
|
||||
|
||||
Vendored
-202
@@ -1,202 +0,0 @@
|
||||
# Copyright 2012 (C) Daniel Richman, Adam Greig
|
||||
#
|
||||
# This file is part of strict_rfc3339.
|
||||
#
|
||||
# strict_rfc3339 is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# strict_rfc3339 is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with strict_rfc3339. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
"""
|
||||
Super simple lightweight RFC3339 functions
|
||||
"""
|
||||
|
||||
import re
|
||||
import time
|
||||
import calendar
|
||||
|
||||
__all__ = ["validate_rfc3339",
|
||||
"InvalidRFC3339Error",
|
||||
"rfc3339_to_timestamp",
|
||||
"timestamp_to_rfc3339_utcoffset",
|
||||
"timestamp_to_rfc3339_localoffset",
|
||||
"now_to_rfc3339_utcoffset",
|
||||
"now_to_rfc3339_localoffset"]
|
||||
|
||||
rfc3339_regex = re.compile(
|
||||
r"^(\d\d\d\d)\-(\d\d)\-(\d\d)T"
|
||||
r"(\d\d):(\d\d):(\d\d)(\.\d+)?(Z|([+\-])(\d\d):(\d\d))$")
|
||||
|
||||
|
||||
def validate_rfc3339(datestring):
|
||||
"""Check an RFC3339 string is valid via a regex and some range checks"""
|
||||
|
||||
m = rfc3339_regex.match(datestring)
|
||||
if m is None:
|
||||
return False
|
||||
|
||||
groups = m.groups()
|
||||
|
||||
year, month, day, hour, minute, second = [int(i) for i in groups[:6]]
|
||||
|
||||
if not 1 <= year <= 9999:
|
||||
# Have to reject this, unfortunately (despite it being OK by rfc3339):
|
||||
# calendar.timegm/calendar.monthrange can't cope (since datetime can't)
|
||||
return False
|
||||
|
||||
if not 1 <= month <= 12:
|
||||
return False
|
||||
|
||||
(_, max_day) = calendar.monthrange(year, month)
|
||||
if not 1 <= day <= max_day:
|
||||
return False
|
||||
|
||||
if not (0 <= hour <= 23 and 0 <= minute <= 59 and 0 <= second <= 59):
|
||||
# forbid leap seconds :-(. See README
|
||||
return False
|
||||
|
||||
if groups[7] != "Z":
|
||||
(offset_sign, offset_hours, offset_mins) = groups[8:]
|
||||
if not (0 <= int(offset_hours) <= 23 and 0 <= int(offset_mins) <= 59):
|
||||
return False
|
||||
|
||||
# all OK
|
||||
return True
|
||||
|
||||
|
||||
class InvalidRFC3339Error(ValueError):
|
||||
"""Subclass of ValueError thrown by rfc3339_to_timestamp"""
|
||||
pass
|
||||
|
||||
|
||||
def rfc3339_to_timestamp(datestring):
|
||||
"""Convert an RFC3339 date-time string to a UTC UNIX timestamp"""
|
||||
|
||||
if not validate_rfc3339(datestring):
|
||||
raise InvalidRFC3339Error
|
||||
|
||||
groups = rfc3339_regex.match(datestring).groups()
|
||||
|
||||
time_tuple = [int(p) for p in groups[:6]]
|
||||
timestamp = calendar.timegm(time_tuple)
|
||||
|
||||
seconds_part = groups[6]
|
||||
if seconds_part is not None:
|
||||
timestamp += float("0" + seconds_part)
|
||||
|
||||
if groups[7] != "Z":
|
||||
(offset_sign, offset_hours, offset_mins) = groups[8:]
|
||||
offset_seconds = int(offset_hours) * 3600 + int(offset_mins) * 60
|
||||
if offset_sign == '-':
|
||||
offset_seconds = -offset_seconds
|
||||
timestamp -= offset_seconds
|
||||
|
||||
return timestamp
|
||||
|
||||
|
||||
def _seconds_and_microseconds(timestamp):
|
||||
"""
|
||||
Split a floating point timestamp into an integer number of seconds since
|
||||
the epoch, and an integer number of microseconds (having rounded to the
|
||||
nearest microsecond).
|
||||
|
||||
If `_seconds_and_microseconds(x) = (y, z)` then the following holds (up to
|
||||
the error introduced by floating point operations):
|
||||
|
||||
* `x = y + z / 1_000_000.`
|
||||
* `0 <= z < 1_000_000.`
|
||||
"""
|
||||
|
||||
if isinstance(timestamp, int):
|
||||
return (timestamp, 0)
|
||||
else:
|
||||
timestamp_us = int(round(timestamp * 1e6))
|
||||
return divmod(timestamp_us, 1000000)
|
||||
|
||||
def _make_datestring_start(time_tuple, microseconds):
|
||||
ds_format = "{0:04d}-{1:02d}-{2:02d}T{3:02d}:{4:02d}:{5:02d}"
|
||||
datestring = ds_format.format(*time_tuple)
|
||||
|
||||
seconds_part_str = "{0:06d}".format(microseconds)
|
||||
# There used to be a bug here where it could be 1000000
|
||||
assert len(seconds_part_str) == 6 and seconds_part_str[0] != '-'
|
||||
seconds_part_str = seconds_part_str.rstrip("0")
|
||||
if seconds_part_str != "":
|
||||
datestring += "." + seconds_part_str
|
||||
|
||||
return datestring
|
||||
|
||||
|
||||
def timestamp_to_rfc3339_utcoffset(timestamp):
|
||||
"""Convert a UTC UNIX timestamp to RFC3339, with the offset as 'Z'"""
|
||||
|
||||
seconds, microseconds = _seconds_and_microseconds(timestamp)
|
||||
|
||||
time_tuple = time.gmtime(seconds)
|
||||
datestring = _make_datestring_start(time_tuple, microseconds)
|
||||
datestring += "Z"
|
||||
|
||||
assert abs(rfc3339_to_timestamp(datestring) - timestamp) < 0.000001
|
||||
return datestring
|
||||
|
||||
|
||||
def timestamp_to_rfc3339_localoffset(timestamp):
|
||||
"""
|
||||
Convert a UTC UNIX timestamp to RFC3339, using the local offset.
|
||||
|
||||
localtime() provides the time parts. The difference between gmtime and
|
||||
localtime tells us the offset.
|
||||
"""
|
||||
|
||||
seconds, microseconds = _seconds_and_microseconds(timestamp)
|
||||
|
||||
time_tuple = time.localtime(seconds)
|
||||
datestring = _make_datestring_start(time_tuple, microseconds)
|
||||
|
||||
gm_time_tuple = time.gmtime(seconds)
|
||||
offset = calendar.timegm(time_tuple) - calendar.timegm(gm_time_tuple)
|
||||
|
||||
if abs(offset) % 60 != 0:
|
||||
raise ValueError("Your local offset is not a whole minute")
|
||||
|
||||
offset_minutes = abs(offset) // 60
|
||||
offset_hours = offset_minutes // 60
|
||||
offset_minutes %= 60
|
||||
|
||||
offset_string = "{0:02d}:{1:02d}".format(offset_hours, offset_minutes)
|
||||
|
||||
if offset < 0:
|
||||
datestring += "-"
|
||||
else:
|
||||
datestring += "+"
|
||||
|
||||
datestring += offset_string
|
||||
assert abs(rfc3339_to_timestamp(datestring) - timestamp) < 0.000001
|
||||
|
||||
return datestring
|
||||
|
||||
|
||||
def now_to_rfc3339_utcoffset(integer=True):
|
||||
"""Convert the current time to RFC3339, with the offset as 'Z'"""
|
||||
|
||||
timestamp = time.time()
|
||||
if integer:
|
||||
timestamp = int(timestamp)
|
||||
return timestamp_to_rfc3339_utcoffset(timestamp)
|
||||
|
||||
|
||||
def now_to_rfc3339_localoffset(integer=True):
|
||||
"""Convert the current time to RFC3339, using the local offset."""
|
||||
|
||||
timestamp = time.time()
|
||||
if integer:
|
||||
timestamp = int(timestamp)
|
||||
return timestamp_to_rfc3339_localoffset(timestamp)
|
||||
Vendored
-9
@@ -1,9 +0,0 @@
|
||||
import sys
|
||||
|
||||
def timestamp(d=None):
|
||||
import datetime
|
||||
import time
|
||||
return int(time.mktime(d.timetuple()) * 1000) if d else int(time.time() * 1000)
|
||||
|
||||
sys.modules[__name__] = timestamp
|
||||
|
||||
@@ -1,14 +1,21 @@
|
||||
# Make sure we use the patched packages.
|
||||
# We need to import the patched packages directly from sys.path, so the
|
||||
# identity checks can pass.
|
||||
import pipenv # noqa
|
||||
|
||||
import datetime
|
||||
import os
|
||||
|
||||
from prettytoml import lexer
|
||||
import pytest
|
||||
import pytz
|
||||
|
||||
from pipfile.api import PipfileParser
|
||||
from prettytoml import lexer, tokens
|
||||
from prettytoml.elements.atomic import AtomicElement
|
||||
from prettytoml.elements.metadata import (
|
||||
WhitespaceElement, PunctuationElement, CommentElement
|
||||
)
|
||||
from prettytoml.elements.table import TableElement
|
||||
from pipenv.patched.pipfile.api import PipfileParser
|
||||
from prettytoml.tokens.py2toml import create_primitive_token
|
||||
|
||||
|
||||
def test_table():
|
||||
@@ -62,3 +69,38 @@ class TestPipfileParser:
|
||||
assert parsed_dict["list"][1] == {}
|
||||
assert parsed_dict["bool"] is True
|
||||
assert parsed_dict["none"] is None
|
||||
|
||||
|
||||
@pytest.mark.parametrize('dt, content', [
|
||||
( # Date.
|
||||
datetime.date(1992, 8, 19),
|
||||
'1992-08-19',
|
||||
),
|
||||
( # Naive time.
|
||||
datetime.time(15, 10),
|
||||
'15:10:00',
|
||||
),
|
||||
( # Aware time in UTC.
|
||||
datetime.time(15, 10, tzinfo=pytz.UTC),
|
||||
'15:10:00Z',
|
||||
),
|
||||
( # Aware local time.
|
||||
datetime.time(15, 10, tzinfo=pytz.FixedOffset(8 * 60)),
|
||||
'15:10:00+08:00',
|
||||
),
|
||||
( # Naive datetime.
|
||||
datetime.datetime(1992, 8, 19, 15, 10),
|
||||
'1992-08-19T15:10:00',
|
||||
),
|
||||
( # Aware datetime in UTC.
|
||||
datetime.datetime(1992, 8, 19, 15, 10, tzinfo=pytz.UTC),
|
||||
'1992-08-19T15:10:00Z',
|
||||
),
|
||||
( # Aware local datetime.
|
||||
datetime.datetime(1992, 8, 19, 15, 10, tzinfo=pytz.FixedOffset(8 * 60)),
|
||||
'1992-08-19T15:10:00+08:00',
|
||||
),
|
||||
])
|
||||
def test_token_date(dt, content):
|
||||
token = create_primitive_token(dt)
|
||||
assert token == tokens.Token(tokens.TYPE_DATE, content)
|
||||
|
||||
Reference in New Issue
Block a user