closeio / ciso8601 Goto Github PK
View Code? Open in Web Editor NEWFast ISO8601 date time parser for Python written in C
License: MIT License
Fast ISO8601 date time parser for Python written in C
License: MIT License
As it stands, there are a number of actions needed in order to release a new version of ciso8601
VERSION
in setup.py
CHANGELOG.md
We should be able to automate (nearly?) all of this.
We can use GitHub Actions to automate (nearly?) everything. Here's my current thinking of how it would work. I'm testing these configurations out on this test repo.
I imagine it being broken up into three GitHub Actions:
A developer pushes a tag that matches our expected version number format: v1.2.3
The build of the wheels is complete in CircleCI, and a webhook is sent to GitHub.
This is not trivial.
CircleCI no longer has first-party support for sending webhooks on build completion. Instead, you are supposed to use a "notification orb" to do it. I found an orb that sends a webhook that looks like how the first-party webhooks from CircleCI used to look like.
GitHub expects a specific format for the webhooks that can trigger a repository_dispatch
event.
I'll likely fork the orb and publish a new orb that formats the webhook exactly how GitHub expects it to be.
When the developer publishes the draft release in the GitHub UI.
This can be done using the convenient pypa/gh-action-pypi-publish
GitHub action, using GitHub repository Secrets
. Secrets are encrypted values that GitHub can decrypt within the GitHub Action containers. That way, no one ever sees the decrypted values, and means that maintainers can be given the ability to publish to PyPI without needing the keys to the kingdom. Further, the secret would be a PyPI token that can be scoped to only work for this specific project.
This is what a developer would have to do after this automation was in place:
GitHub Workflows can't trigger other workflows. But workflows can be triggered by the completion of other workflows (workflow_run
).
The important distinction is that there is no way (AFAIK) to pass the parameters from the upstream workflow to the downstream one.
There are many state changes described by this automation. Since these are not being done within any form of transaction, it will be important that each step is idempotent, so that the process can be simply restarted/retried without worrying about the state of the system after the failure.
Speaking of retries, there needs to be mechanisms to manually trigger retries in cases of failures. Neither GitHub nor CircleCI make this easy. In GitHub, you can use the workflow_dispatch
trigger to manually trigger a workflow, though providing the same parameters that they workflow needs does not seem to be trivial. For example, I haven't yet figured out (I haven't put any effort into it yet either) how to do github.ref || github.event.inputs.ref
yet.
In CircleCI, you can guard a workflow with a when
clause and then the only way to trigger that workflow is via a POST to the API.
CircleCI allows for arbitrary Docker containers for your builds, while GitHub Actions only provides a few "blessed" runners.
Since we are hoping to use the manylinux docker containers as part of the build, we cannot switch entirely to GitHub Actions.
Hi Guys,
I'm having a hard time trying to install ciso8601==2.1.3
I already installed the wheel package (saw it on another issue).
Can you suggest a way to get it right?
Ubuntu 18.04
python 3.6.9
pip 9.0.1
(venv) v4l3nt1n@v4l3nt1n-nb:~/_work/_dev/_dw/_dev/process-machine-project$ pip install ciso8601
Collecting ciso8601
Using cached https://files.pythonhosted.org/packages/2c/da/626910cf8aca7ed2d5b34355eee8aeaaeb6ddd4e16f98d00a9e2ddad3a08/ciso8601-2.1.3.tar.gz
Building wheels for collected packages: ciso8601
Running setup.py bdist_wheel for ciso8601 ... error
Complete output from command /home/v4l3nt1n/_work/_dev/_dw/_dev/process-machine-project/venv/bin/python3.6 -u -c "import setuptools, tokenize;file='/tmp/pip-build-j0oq0ixx/ciso8601/setup.py';f=getattr(tokenize, 'open', open)(file);code=f.read().replace('\r\n', '\n');f.close();exec(compile(code, file, 'exec'))" bdist_wheel -d /tmp/tmpbfg9puakpip-wheel- --python-tag cp36:
running bdist_wheel
running build
running build_py
package init file 'ciso8601/init.py' not found (or not a regular file)
creating build
creating build/lib.linux-x86_64-3.6
creating build/lib.linux-x86_64-3.6/ciso8601
copying ciso8601/init.pyi -> build/lib.linux-x86_64-3.6/ciso8601
copying ciso8601/py.typed -> build/lib.linux-x86_64-3.6/ciso8601
running build_ext
building 'ciso8601' extension
creating build/temp.linux-x86_64-3.6
x86_64-linux-gnu-gcc -pthread -DNDEBUG -g -fwrapv -O2 -Wall -g -fstack-protector-strong -Wformat -Werror=format-security -Wdate-time -D_FORTIFY_SOURCE=2 -fPIC -DCISO8601_VERSION=2.1.3 -I/home/v4l3nt1n/_work/_dev/_dw/_dev/process-machine-project/venv/include -I/usr/include/python3.6m -c module.c -o build/temp.linux-x86_64-3.6/module.o
unable to execute 'x86_64-linux-gnu-gcc': No such file or directory
error: command 'x86_64-linux-gnu-gcc' failed with exit status 1
Failed building wheel for ciso8601
Running setup.py clean for ciso8601
Failed to build ciso8601
Installing collected packages: ciso8601
Running setup.py install for ciso8601 ... error
Complete output from command /home/v4l3nt1n/_work/_dev/_dw/_dev/process-machine-project/venv/bin/python3.6 -u -c "import setuptools, tokenize;file='/tmp/pip-build-j0oq0ixx/ciso8601/setup.py';f=getattr(tokenize, 'open', open)(file);code=f.read().replace('\r\n', '\n');f.close();exec(compile(code, file, 'exec'))" install --record /tmp/pip-7xs_tlks-record/install-record.txt --single-version-externally-managed --compile --install-headers /home/v4l3nt1n/_work/_dev/_dw/_dev/process-machine-project/venv/include/site/python3.6/ciso8601:
running install
running build
running build_py
package init file 'ciso8601/init.py' not found (or not a regular file)
creating build
creating build/lib.linux-x86_64-3.6
creating build/lib.linux-x86_64-3.6/ciso8601
copying ciso8601/init.pyi -> build/lib.linux-x86_64-3.6/ciso8601
copying ciso8601/py.typed -> build/lib.linux-x86_64-3.6/ciso8601
running build_ext
building 'ciso8601' extension
creating build/temp.linux-x86_64-3.6
x86_64-linux-gnu-gcc -pthread -DNDEBUG -g -fwrapv -O2 -Wall -g -fstack-protector-strong -Wformat -Werror=format-security -Wdate-time -D_FORTIFY_SOURCE=2 -fPIC -DCISO8601_VERSION=2.1.3 -I/home/v4l3nt1n/_work/_dev/_dw/_dev/process-machine-project/venv/include -I/usr/include/python3.6m -c module.c -o build/temp.linux-x86_64-3.6/module.o
unable to execute 'x86_64-linux-gnu-gcc': No such file or directory
error: command 'x86_64-linux-gnu-gcc' failed with exit status 1
----------------------------------------
Command "/home/v4l3nt1n/_work/_dev/_dw/_dev/process-machine-project/venv/bin/python3.6 -u -c "import setuptools, tokenize;file='/tmp/pip-build-j0oq0ixx/ciso8601/setup.py';f=getattr(tokenize, 'open', open)(file);code=f.read().replace('\r\n', '\n');f.close();exec(compile(code, file, 'exec'))" install --record /tmp/pip-7xs_tlks-record/install-record.txt --single-version-externally-managed --compile --install-headers /home/v4l3nt1n/_work/_dev/_dw/_dev/process-machine-project/venv/include/site/python3.6/ciso8601" failed with error code 1 in /tmp/pip-build-j0oq0ixx/ciso8601/
Thank you very much for this lib and work!!
Hi all,
I'm trying to do a simple pip install on Windows 10, but I get the below error when trying to do so:
C:\Users\marti>pip install ciso8601
Collecting ciso8601
Using cached ciso8601-2.1.3.tar.gz (15 kB)
Building wheels for collected packages: ciso8601
Building wheel for ciso8601 (setup.py) ... error
ERROR: Command errored out with exit status 1:
command: 'c:\users\marti\appdata\local\programs\python\python37\python.exe' -u -c 'import sys, setuptools, tokenize; sys.argv[0] = '"'"'C:\\Users\\marti\\AppData\\Local\\Temp\\pip-install-uret8oh9\\ciso8601\\setup.py'"'"'; __file__='"'"'C:\\Users\\marti\\AppData\\Local\\Temp\\pip-install-uret8oh9\\ciso8601\\setup.py'"'"';f=getattr(tokenize, '"'"'open'"'"', open)(__file__);code=f.read().replace('"'"'\r\n'"'"', '"'"'\n'"'"');f.close();exec(compile(code, __file__, '"'"'exec'"'"'))' bdist_wheel -d 'C:\Users\marti\AppData\Local\Temp\pip-wheel-rd64cadi'
cwd: C:\Users\marti\AppData\Local\Temp\pip-install-uret8oh9\ciso8601\
Complete output (17 lines):
running bdist_wheel
running build
running build_py
package init file 'ciso8601\__init__.py' not found (or not a regular file)
creating build
creating build\lib.win-amd64-3.7
creating build\lib.win-amd64-3.7\ciso8601
copying ciso8601\__init__.pyi -> build\lib.win-amd64-3.7\ciso8601
copying ciso8601\py.typed -> build\lib.win-amd64-3.7\ciso8601
running build_ext
building 'ciso8601' extension
creating build\temp.win-amd64-3.7
creating build\temp.win-amd64-3.7\Release
C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Tools\MSVC\14.14.26428\bin\HostX86\x64\cl.exe /c /nologo /Ox /W3 /GL /DNDEBUG /MD -DCISO8601_VERSION=2.1.3 -Ic:\users\marti\appdata\local\programs\python\python37\include -Ic:\users\marti\appdata\local\programs\python\python37\include "-IC:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Tools\MSVC\14.14.26428\ATLMFC\include" "-IC:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Tools\MSVC\14.14.26428\include" "-IC:\Program Files (x86)\Windows Kits\NETFXSDK\4.6.1\include\um" /Tcmodule.c /Fobuild\temp.win-amd64-3.7\Release\module.obj
module.c
c:\users\marti\appdata\local\programs\python\python37\include\pyconfig.h(59): fatal error C1083: Cannot open include file: 'io.h': No such file or directory
error: command 'C:\\Program Files (x86)\\Microsoft Visual Studio\\2017\\Community\\VC\\Tools\\MSVC\\14.14.26428\\bin\\HostX86\\x64\\cl.exe' failed with exit status 2
----------------------------------------
ERROR: Failed building wheel for ciso8601
Running setup.py clean for ciso8601
Failed to build ciso8601
Installing collected packages: ciso8601
Running setup.py install for ciso8601 ... error
ERROR: Command errored out with exit status 1:
command: 'c:\users\marti\appdata\local\programs\python\python37\python.exe' -u -c 'import sys, setuptools, tokenize; sys.argv[0] = '"'"'C:\\Users\\marti\\AppData\\Local\\Temp\\pip-install-uret8oh9\\ciso8601\\setup.py'"'"'; __file__='"'"'C:\\Users\\marti\\AppData\\Local\\Temp\\pip-install-uret8oh9\\ciso8601\\setup.py'"'"';f=getattr(tokenize, '"'"'open'"'"', open)(__file__);code=f.read().replace('"'"'\r\n'"'"', '"'"'\n'"'"');f.close();exec(compile(code, __file__, '"'"'exec'"'"'))' install --record 'C:\Users\marti\AppData\Local\Temp\pip-record-5qx55zzz\install-record.txt' --single-version-externally-managed --compile --install-headers 'c:\users\marti\appdata\local\programs\python\python37\Include\ciso8601'
cwd: C:\Users\marti\AppData\Local\Temp\pip-install-uret8oh9\ciso8601\
Complete output (17 lines):
running install
running build
running build_py
package init file 'ciso8601\__init__.py' not found (or not a regular file)
creating build
creating build\lib.win-amd64-3.7
creating build\lib.win-amd64-3.7\ciso8601
copying ciso8601\__init__.pyi -> build\lib.win-amd64-3.7\ciso8601
copying ciso8601\py.typed -> build\lib.win-amd64-3.7\ciso8601
running build_ext
building 'ciso8601' extension
creating build\temp.win-amd64-3.7
creating build\temp.win-amd64-3.7\Release
C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Tools\MSVC\14.14.26428\bin\HostX86\x64\cl.exe /c /nologo /Ox /W3 /GL /DNDEBUG /MD -DCISO8601_VERSION=2.1.3 -Ic:\users\marti\appdata\local\programs\python\python37\include -Ic:\users\marti\appdata\local\programs\python\python37\include "-IC:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Tools\MSVC\14.14.26428\ATLMFC\include" "-IC:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Tools\MSVC\14.14.26428\include" "-IC:\Program Files (x86)\Windows Kits\NETFXSDK\4.6.1\include\um" /Tcmodule.c /Fobuild\temp.win-amd64-3.7\Release\module.obj
module.c
c:\users\marti\appdata\local\programs\python\python37\include\pyconfig.h(59): fatal error C1083: Cannot open include file: 'io.h': No such file or directory
error: command 'C:\\Program Files (x86)\\Microsoft Visual Studio\\2017\\Community\\VC\\Tools\\MSVC\\14.14.26428\\bin\\HostX86\\x64\\cl.exe' failed with exit status 2
----------------------------------------
ERROR: Command errored out with exit status 1: 'c:\users\marti\appdata\local\programs\python\python37\python.exe' -u -c 'import sys, setuptools, tokenize; sys.argv[0] = '"'"'C:\\Users\\marti\\AppData\\Local\\Temp\\pip-install-uret8oh9\\ciso8601\\setup.py'"'"'; __file__='"'"'C:\\Users\\marti\\AppData\\Local\\Temp\\pip-install-uret8oh9\\ciso8601\\setup.py'"'"';f=getattr(tokenize, '"'"'open'"'"', open)(__file__);code=f.read().replace('"'"'\r\n'"'"', '"'"'\n'"'"');f.close();exec(compile(code, __file__, '"'"'exec'"'"'))' install --record 'C:\Users\marti\AppData\Local\Temp\pip-record-5qx55zzz\install-record.txt' --single-version-externally-managed --compile --install-headers 'c:\users\marti\appdata\local\programs\python\python37\Include\ciso8601' Check the logs for full command output.
>>> ciso8601.parse_datetime('2001-01-01T24:01:01')
datetime.datetime(2001, 1, 1, 24, 1, 1)
This should raise an exception.
Potential users should be able to compare the capabilities of ciso8601
with other popular ISO 8601 parsers.
Other parsers might look attractive at first glance, but many have bugs or limitations.
ciso8601
itself has some limitations (I think we already do a good job of documenting that though).
Other libraries have limited support for platforms (ex. udatetime
doesn't support Windows).
Make a comparison document or chart that will help people see the differences between the libraries.
A missing minutes fragment between two time separators should cause it to stop parsing and consider the rest of the string junk, but instead it treats minutes as zero.
Test:
ciso8601.parse_datetime('20140203T10::27')
Expected:
datetime.datetime(2014, 2, 3, 10, 0)
Actual:
datetime.datetime(2014, 2, 3, 10, 0, 27)
This isn't legal under ISO 8601 and should throw an error:
>>> ciso8601.parse_datetime('20010203T04:05:06Z')
datetime.datetime(2001, 2, 3, 4, 5, 6, tzinfo=datetime.timezone.utc)
So should this:
>>> ciso8601.parse_datetime('20010203T04:05')
datetime.datetime(2001, 2, 3, 4, 5)
The first is forbidden by the combination of section 4.3.2, which specifies the format for "complete" date and time representations, and section 4.4.4, about date interval representations. Section 4.3.2 says:
The hyphen [-] and the colon [:] shall be used, in accordance with 4.4.4, as separators within the date and time of day expressions, respectively, when required.
And section 4.4.4.1, says:
When the application identifies the need for a complete representation of a time interval, identified by its start and its end, it shall use an expression in accordance with 4.4.2 combining any two complete date and time of day representations as defined in 4.3.2, provided that the resulting expression is either consistently in basic format or consistently in extended format.
It's kind of weird that the section about how to represent complete datetimes basically says "Hey, to know all the rules about how to do this, go forward in the spec and read the unrelated section about datetime intervals, because we actually put some of our rules about what a legal datetime representation in there for some reason", but as far as I can tell that's exactly what section 4.3.2 says. It would've been more natural to put all the rules about what a legal complete datetime representation is in the section about complete datetime representations and refer back to that from the section about intervals, but that's not what the authors did. Meh.
The second example I gave above, with a "reduced accuracy" datetime, is more straightforward; it's banned by section 4.3.3, which says
For reduced accuracy, decimal or expanded representations of date and time of day, any of the
representations in [bla] followed immediately by the time designator [T] may be combined with any of the representations in [bla] provided thata) [bla];
b) [bla];
c) [bla];
d) the expression shall either be completely in basic format, in which case the minimum number of separators necessary for the required expression is used, or completely in extended format, in which case additional separators shall be used in accordance with 4.1 and 4.2.
I'm not sure if this is a performance feature, or bug, but the library currently doesn't throw exceptions when numeric date string parameters are outside the respected time field's range, i.e. setting a month to a value greater than 12 yields:
import ciso8601
print(ciso8601.parse_datetime('2014-13-01'))
2014-13-01 00:00:00.
I am wondering if this is the intended feature as a Python datetime object will throw a ValueError in this situation?
Python 3.7 added datetime.fromisoformat
to the datetime library, which might be another target to add to the benchmarks without timezones for completeness.
Now a few remarks about the function:
isoformat
, so it isn't super flexible compared to what you providestrptime
, it is still implemented in pure Python, so it's highly unlikely to beat your implementation.The codebase of ciso8601 is a mix of various C coding/formatting styles.
The classic example in C is where opening {
should go. In ciso8601, we have examples of both:
ciso8601
should specify a C formatting style and enforce it.
This could then be put into a .clang-format
file, so that developer's IDE's could enforce the style as they code.
While I don't care which format is chosen, I do want ciso8601 to have a consistent style and for my contributions to match that style.
When ciso8601
was first created, there were no reasonable alternatives to it. By virtue of being implemented in C, it was simply much faster than Python implementations.
However, time have moved on, and there are viable alternatives, so the choice is more nuanced.
For example, as of Python 3.7, there exists datetime.fromisoformat
that provides the inverse of datetime.isoformat
. While it is not a complete replacement for ciso8601
(ex. it doesn't support formats like YYYYMMDD
), for users that were only ever using ciso8601 to provide that inverse, they might be better served by using fromisoformat
.
Further, the Pendulum project has implemented a fast C parser as well. While pendulum will be slower, they support a wider subset of the ISO 8601 spec.
So there is now a spectrum of quality parsers that users might want to use:
datetime.isoformat ciso8601 pendulum
<----- Performance Completeness ----->
It might be time for ciso8601
to change its marketing to be more nuanced. Originally, when there were no real alternatives, it made sense to say:
"We're the best, no questions. Use ciso8601."
But perhaps now we should be doing something similar to a flow-chart:
- If you only need support for Python 3.7, and just need an inverse to
isoformat
, usedatetime.fromisoformat
.- If you only need to parse datetimes with the most common subset of ISO 8601, use
ciso8601
.- If you need to parse datetimes with the entire ISO 8601 spec, use
pendulum
.
(Aside: I backported fromisoformat
to pre-Python 3.7 versions: )
From a practical standpoint, this would involve mentioning alternatives in ciso8601
's README (or perhaps a new document). It would also mean rewriting any other docs to tone down any rhetoric.
(Aside: In general, I'd like to see more collaboration between the various ISO 8601 parse projects, especially Pendulum
and udatetime
)
When installing ciso8601 as a package dependency, using Python 3 and C locale:
Searching for ciso8601
Reading https://pypi.python.org/simple/ciso8601/
Downloading https://pypi.python.org/packages/06/2e/2d7b09bb667bd7d862838c1ab7d0dd06be1de27ff60a7c1b0fb0db53fc93/ciso8601-1.0.5.tar.gz#md5=831bbf799722d34a5e60d91e1fd63cd6
Best match: ciso8601 1.0.5
Processing ciso8601-1.0.5.tar.gz
Writing /tmp/easy_install-b_gqrezf/ciso8601-1.0.5/setup.cfg
Running ciso8601-1.0.5/setup.py -q bdist_egg --dist-dir /tmp/easy_install-b_gqrezf/ciso8601-1.0.5/egg-dist-tmp-e66bnce5
Traceback (most recent call last):
File "/var/lib/arvados/test/VENV3DIR/lib/python3.5/site-packages/setuptools/sandbox.py", line 158, in save_modules
yield saved
File "/var/lib/arvados/test/VENV3DIR/lib/python3.5/site-packages/setuptools/sandbox.py", line 199, in setup_context
yield
File "/var/lib/arvados/test/VENV3DIR/lib/python3.5/site-packages/setuptools/sandbox.py", line 254, in run_setup
_execfile(setup_script, ns)
File "/var/lib/arvados/test/VENV3DIR/lib/python3.5/site-packages/setuptools/sandbox.py", line 49, in _execfile
exec(code, globals, locals)
File "/tmp/easy_install-b_gqrezf/ciso8601-1.0.5/setup.py", line 4, in <module>
# SPDX-License-Identifier: Apache-2.0
File "/var/lib/arvados/test/VENV3DIR/lib/python3.5/encodings/ascii.py", line 26, in decode
return codecs.ascii_decode(input, self.errors)[0]
UnicodeDecodeError: 'ascii' codec can't decode byte 0xc2 in position 1561: ordinal not in range(128)
This is caused by non-ASCII character "µs" in README.rst
With some googling I found a discussion about this same problem relating to a different package:
pls, add support for python version >= 3.9.
dt = '2017-0012-27T13:35:19+0200'
boom = ciso8601.parse_datetime(dt)
causes segmentation fault
>>> datetime.datetime(2016, 11, 31)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: day is out of range for month
>>> ciso8601.parse_datetime_unaware("2016-11-31T12:34:34.521059")
datetime.datetime(2016, 11, 31, 12, 34, 34, 521059)
>>> datetime.datetime(2016, 11, 31, 12, 34, 34, 521059)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: day is out of range for month
>>>
A missing seconds fragment between two time separators should cause it to stop parsing and consider the rest of the string junk, but instead it treats seconds as zero.
Test:
ciso8601.parse_datetime('20140203 04:05:.123456')
Expected:
datetime.datetime(2014, 2, 3, 4, 5)
Actual:
datetime.datetime(2014, 2, 3, 4, 5, 0, 123456)
I came across this silent failure when parsing a third party datetime with an unusual separator:
>>> import ciso8601
>>> ciso8601.parse_datetime('2017-05-29 17:36:00Z')
datetime.datetime(2017, 5, 29, 17, 36, tzinfo=<UTC>)
#Now for a completely invalid string
>>> print(ciso8601.parse_datetime('Completely invalid!'))
None
#Now for an out of spec string (invalid separator)
>>> ciso8601.parse_datetime('2017-05-29_17:36:00Z')
datetime.datetime(2017, 5, 29, 0, 0)
It seems that the parser sees a character that it doesn't recognize and stops parsing?
I would have expected that if the entire string cannot be parsed, it would return None
as parse_datetime
does for other parse failures, not silently return a datetime without time or tzinfo
.
This lead to a sneaky bug in the code.
I have versions:
$ pypy3 --version
Python 3.7.9 (7e6e2bb30ac5fbdbd443619cae28c51d5c162a02, Nov 24 2020, 10:03:59)
[PyPy 7.3.3-beta0 with GCC 10.2.0]
$ gcc --version
gcc (GCC) 10.2.0
When I run CFLAGS="$CFLAGS -fcommon" pypy3 -m pip install git+https://github.com/closeio/ciso8601.git
, I get:
Defaulting to user installation because normal site-packages is not writeable
Collecting git+https://github.com/closeio/ciso8601.git
Cloning https://github.com/closeio/ciso8601.git to /tmp/pip-req-build-zank7ym7
Running command git clone -q https://github.com/closeio/ciso8601.git /tmp/pip-req-build-zank7ym7
Building wheels for collected packages: ciso8601
Building wheel for ciso8601 (setup.py): started
Building wheel for ciso8601 (setup.py): finished with status 'error'
ERROR: Command errored out with exit status 1:
command: /usr/bin/pypy3 -u -c 'import sys, setuptools, tokenize; sys.argv[0] = '"'"'/tmp/pip-req-build-zank7ym7/setup.py'"'"'; __file__='"'"'/tmp/pip-req-build-zank7ym7/setup.py'"'"';f=getattr(tokenize, '"'"'open'"'"', open)(__file__);code=f.read().replace('"'"'\r\n'"'"', '"'"'\n'"'"');f.close();exec(compile(code, __file__, '"'"'exec'"'"'))' bdist_wheel -d /tmp/pip-wheel-k0gy_icr
cwd: /tmp/pip-req-build-zank7ym7/
Complete output (27 lines):
running bdist_wheel
running build
running build_py
package init file 'ciso8601/__init__.py' not found (or not a regular file)
creating build
creating build/lib.linux-x86_64-3.7
creating build/lib.linux-x86_64-3.7/ciso8601
copying ciso8601/__init__.pyi -> build/lib.linux-x86_64-3.7/ciso8601
copying ciso8601/py.typed -> build/lib.linux-x86_64-3.7/ciso8601
running build_ext
building 'ciso8601' extension
creating build/temp.linux-x86_64-3.7
gcc -pthread -DNDEBUG -O2 -O2 -march=broadwell -mmmx -mno-3dnow -msse -msse2 -msse3 -mssse3 -mno-sse4a -mcx16 -msahf -mmovbe -maes -mno-sha -mpclmul -mpopcnt -mabm -mno-lwp -mfma -mno-fma4 -mno-xop -mbmi -mno-sgx -mbmi2 -mno-pconfig -mno-wbnoinvd -mno-tbm -mavx -mavx2 -msse4.2 -msse4.1 -mlzcnt -mrtm -mhle -mrdrnd -mf16c -mfsgsbase -mrdseed -mprfchw -madx -mfxsr -mxsave -mxsaveopt -mno-avx512f -mno-avx512er -mno-avx512cd -mno-avx512pf -mno-prefetchwt1 -mno-clflushopt -mno-xsavec -mno-xsaves -mno-avx512dq -mno-avx512bw -mno-avx512vl -mno-avx512ifma -mno-avx512vbmi -mno-avx5124fmaps -mno-avx5124vnniw -mno-clwb -mno-mwaitx -mno-clzero -mno-pku -mno-rdpid -mno-gfni -mno-shstk -mno-avx512vbmi2 -mno-avx512vnni -mno-vaes -mno-vpclmulqdq -mno-avx512bitalg -mno-movdiri -mno-movdir64b -mno-waitpkg -mno-cldemote -mno-ptwrite -mtune=broadwell -pipe -fstack-protector-explicit -fno-plt -g -gdwarf -gz -ggdb -Wno-error=deprecated-declarations -fcommon -fPIC -DCISO8601_VERSION=2.1.3 -I/opt/pypy3/include -c module.c -o build/temp.linux-x86_64-3.7/module.o
module.c: In function ‘_parse’:
module.c:446:30: warning: implicit declaration of function ‘PyTimeZone_FromOffset’ [-Wimplicit-function-declaration]
446 | tzinfo = PyTimeZone_FromOffset(delta);
| ^~~~~~~~~~~~~~~~~~~~~
module.c:446:28: warning: assignment to ‘PyObject *’ {aka ‘struct _object *’} from ‘int’ makes pointer from integer without a cast [-Wint-conversion]
446 | tzinfo = PyTimeZone_FromOffset(delta);
| ^
module.c: In function ‘PyInit_ciso8601’:
module.c:562:11: error: ‘PyDateTime_TimeZone_UTC’ undeclared (first use in this function); did you mean ‘PyDateTime_Time’?
562 | utc = PyDateTime_TimeZone_UTC;
| ^~~~~~~~~~~~~~~~~~~~~~~
| PyDateTime_Time
module.c:562:11: note: each undeclared identifier is reported only once for each function it appears in
error: command 'gcc' failed with exit status 1
----------------------------------------
ERROR: Failed building wheel for ciso8601
Running setup.py clean for ciso8601
Failed to build ciso8601
Installing collected packages: ciso8601
Running setup.py install for ciso8601: started
Running setup.py install for ciso8601: finished with status 'error'
ERROR: Command errored out with exit status 1:
command: /usr/bin/pypy3 -u -c 'import sys, setuptools, tokenize; sys.argv[0] = '"'"'/tmp/pip-req-build-zank7ym7/setup.py'"'"'; __file__='"'"'/tmp/pip-req-build-zank7ym7/setup.py'"'"';f=getattr(tokenize, '"'"'open'"'"', open)(__file__);code=f.read().replace('"'"'\r\n'"'"', '"'"'\n'"'"');f.close();exec(compile(code, __file__, '"'"'exec'"'"'))' install --record /tmp/pip-record-bxkrj8i3/install-record.txt --single-version-externally-managed --user --prefix= --compile --install-headers /home/jeff/.local/include/python3.7/ciso8601
cwd: /tmp/pip-req-build-zank7ym7/
Complete output (27 lines):
running install
running build
running build_py
package init file 'ciso8601/__init__.py' not found (or not a regular file)
creating build
creating build/lib.linux-x86_64-3.7
creating build/lib.linux-x86_64-3.7/ciso8601
copying ciso8601/__init__.pyi -> build/lib.linux-x86_64-3.7/ciso8601
copying ciso8601/py.typed -> build/lib.linux-x86_64-3.7/ciso8601
running build_ext
building 'ciso8601' extension
creating build/temp.linux-x86_64-3.7
gcc -pthread -DNDEBUG -O2 -O2 -march=broadwell -mmmx -mno-3dnow -msse -msse2 -msse3 -mssse3 -mno-sse4a -mcx16 -msahf -mmovbe -maes -mno-sha -mpclmul -mpopcnt -mabm -mno-lwp -mfma -mno-fma4 -mno-xop -mbmi -mno-sgx -mbmi2 -mno-pconfig -mno-wbnoinvd -mno-tbm -mavx -mavx2 -msse4.2 -msse4.1 -mlzcnt -mrtm -mhle -mrdrnd -mf16c -mfsgsbase -mrdseed -mprfchw -madx -mfxsr -mxsave -mxsaveopt -mno-avx512f -mno-avx512er -mno-avx512cd -mno-avx512pf -mno-prefetchwt1 -mno-clflushopt -mno-xsavec -mno-xsaves -mno-avx512dq -mno-avx512bw -mno-avx512vl -mno-avx512ifma -mno-avx512vbmi -mno-avx5124fmaps -mno-avx5124vnniw -mno-clwb -mno-mwaitx -mno-clzero -mno-pku -mno-rdpid -mno-gfni -mno-shstk -mno-avx512vbmi2 -mno-avx512vnni -mno-vaes -mno-vpclmulqdq -mno-avx512bitalg -mno-movdiri -mno-movdir64b -mno-waitpkg -mno-cldemote -mno-ptwrite -mtune=broadwell -pipe -fstack-protector-explicit -fno-plt -g -gdwarf -gz -ggdb -Wno-error=deprecated-declarations -fcommon -fPIC -DCISO8601_VERSION=2.1.3 -I/opt/pypy3/include -c module.c -o build/temp.linux-x86_64-3.7/module.o
module.c: In function ‘_parse’:
module.c:446:30: warning: implicit declaration of function ‘PyTimeZone_FromOffset’ [-Wimplicit-function-declaration]
446 | tzinfo = PyTimeZone_FromOffset(delta);
| ^~~~~~~~~~~~~~~~~~~~~
module.c:446:28: warning: assignment to ‘PyObject *’ {aka ‘struct _object *’} from ‘int’ makes pointer from integer without a cast [-Wint-conversion]
446 | tzinfo = PyTimeZone_FromOffset(delta);
| ^
module.c: In function ‘PyInit_ciso8601’:
module.c:562:11: error: ‘PyDateTime_TimeZone_UTC’ undeclared (first use in this function); did you mean ‘PyDateTime_Time’?
562 | utc = PyDateTime_TimeZone_UTC;
| ^~~~~~~~~~~~~~~~~~~~~~~
| PyDateTime_Time
module.c:562:11: note: each undeclared identifier is reported only once for each function it appears in
error: command 'gcc' failed with exit status 1
----------------------------------------
ERROR: Command errored out with exit status 1: /usr/bin/pypy3 -u -c 'import sys, setuptools, tokenize; sys.argv[0] = '"'"'/tmp/pip-req-build-zank7ym7/setup.py'"'"'; __file__='"'"'/tmp/pip-req-build-zank7ym7/setup.py'"'"';f=getattr(tokenize, '"'"'open'"'"', open)(__file__);code=f.read().replace('"'"'\r\n'"'"', '"'"'\n'"'"');f.close();exec(compile(code, __file__, '"'"'exec'"'"'))' install --record /tmp/pip-record-bxkrj8i3/install-record.txt --single-version-externally-managed --user --prefix= --compile --install-headers /home/jeff/.local/include/python3.7/ciso8601 Check the logs for full command output.
Primary issue appears to be missing PyDateTime_TimeZone_UTC
, which is new in Python 3.7 but this version of PyPy claims to implement Python 3.7.
GCC 10 causes these issues sometimes since it switched to the default of -fno-common
, but that doesn't seem to matter here since adding -fcommon
to the CFLAGS doesn't change anything.
When I joined the project, there were a bunch of process things I had to learn.
I would like to create a CONTRIBUTING.md
file, that would document the goals of the project, the tooling, and the process for contributing (see Atom for a complicated example).
In #52 and #54, we made the compilation step fail if there were any warnings.
This is great for the detection of potential issues during development and PR review.
However, it is not great for production releases. ciso8601
is a source distribution, so each user compiles it with each installation. Users with exotic compiler configurations would have the installation of ciso8601 fail, because their compiler might be pickier about what it warns about.
Make ciso8601
only treat warnings as errors during development and PR review, and not during release installations.
I need to parse millions of rows and raising exception could slow down the process. Is there any way to return None or just the same object?
import ciso8601
dt_ciso = ciso8601.parse_datetime('2021-01-01T12:12:01Z')
dt_ciso.tzinfo.fromutc(dt_ciso)
fails with ValueError: fromutc: non-None dst() result required
. Previous version of ciso8601 worked (but it used python builtin tzinfo objects)
However, python builtin and pytz implementations work fine.
from datetime import datetime, timedelta, timezone
import pytz
dt_py = datetime(2021,1,1,12,12,1, tzinfo=timezone(timedelta(0)))
dt_py.tzinfo.fromutc(dt_py)
dt_pytz = datetime(2021,1,1,12,12,1, tzinfo=pytz.utc)
dt_pytz.tzinfo.fromutc(dt_pytz)
This is relevant when calling some_datetime.astimezone(instance_of_FixedOffset)
.
The README does not display properly on PyPI (https://pypi.python.org/pypi/ciso8601/1.0.1). The unfortunate result is that it does not give a good image of this otherwise very useful module.
I would guess that naming the file README.rst
would fix this.
hello, so I used ciso8601 in a lambda function but I cannot use it because it is returning this error
{
"errorMessage": "module 'ciso8601' has no attribute 'parse_datetime'",
"errorType": "AttributeError",
"stackTrace": [
" File \"/var/task/convertToUnix/function.py\", line 14, in lambda_handler\n 'date': convert(event['date'])\n",
" File \"/var/task/convertToUnix/function.py\", line 5, in convert\n s = ciso8601.parse_datetime(text)\n"
]
}
this is the code
import json
import ciso8601
import time
def convert(text):
s = ciso8601.parse_datetime(text)
return time.mktime(s.timetuple())
def lambda_handler(event, context):
if event['date'] != None:
response = {
'date': convert(event['date'])
}
else:
response = {
'message':"error no passed date"
}
return response
Hello!
Stumbled on this strange behavior, consider myself as a bug, what do you think?
Python 3.8.1 (v3.8.1:1b293b6006, Dec 18 2019, 14:08:53)
[Clang 6.0 (clang-600.0.57)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import ciso8601
>>> ciso8601.parse_datetime("2020-02-28T23:00:00Z")
datetime.datetime(2020, 2, 28, 23, 0, tzinfo=datetime.timezone.utc)
>>> ciso8601.parse_datetime("2020-02-28T24:00:00Z")
datetime.datetime(2020, 2, 29, 0, 0, tzinfo=datetime.timezone.utc)
>>> ciso8601.parse_datetime("2020-02-28T25:00:00Z")
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: hour must be in 0..23
It is not only passes "24" hour, but also returns different date. Logic is obvious (next day, 00 hour), but behavior is incorrect IMHO
"2020-02-28T24:00:00Z" != datetime.datetime(2020, 2, 29, 0, 0, tzinfo=datetime.timezone.utc)
Also, 24 is not in range 00..23
Thank you for your good work.
Could you please update a whl file in pypi, so it would be more easy to install when without gcc compiler.
module.c(508): error C2440: 'function': cannot convert from 'double' to 'const char *'
module.c(508): warning C4024: 'PyModule_AddStringConstant': different types for formal and actual parameter 3
module.c(508): error C2143: syntax error: missing ')' before 'constant'
module.c(508): error C2059: syntax error: ')'
error: command 'C:\\Program Files (x86)\\Microsoft Visual Studio\\2017\\Professional\\VC\\Tools\\MSVC\\14.15.26726\\bin\\HostX86\\x64\\cl.exe' failed with exit status 2
Failed building wheel for ciso8601
Python 3.7.0 x64
VS Professional 2017 (15.8.5)
Windows 7 SP1 x64
When parsing data that I know should be in RFC 3339, I'd like a strict mode that rejects non-RFC3339-compliant strings like 2018-07-12
or 2018-07-12T14Z
or 2018-07-12T14:08:12
.
(Mostly, I just want to be sure that I don't end up with a naive datetime when I expected a timezone-aware one, but validating that my data is actually RFC 3339 would be even better.)
It'd be nice to have a parse_rfc3339()
function that is stricter than parse_datetime()
and raises if it gets input that's valid ISO 8601 but not valid RFC 3339.
Starting in Python 3.7, datetime.timezone
objects became accessible through the C-API.
ciso8601 v2.0.0 is scheduled to take advantage of this when compiled against Python 3.7+. The performance improvements are dramatic.
ciso8601 should consider creating a C implementation of a tzinfo subclass. This could be a backport of cPython's timezone class, or a new implementation. Having such an implementation would:
https://gist.github.com/codehack/6350492822e52b7fa7fe
#!/usr/bin/python
import re
# i think i missed a couple of things in 8601 but this should cover 98% of cases.
iso8601 = re.compile(r'^(?P<full>((?P<year>\d{4})([/-]?(?P<mon>(0[1-9])|(1[012]))([/-]?(?P<mday>(0[1-9])|([12]\d)|(3[01])))?)?(?:T(?P<hour>([01][0-9])|(?:2[0123]))(\:?(?P<min>[0-5][0-9])(\:?(?P<sec>[0-5][0-9]([\,\.]\d{1,10})?))?)?(?:Z|([\-+](?:([01][0-9])|(?:2[0123]))(\:?(?:[0-5][0-9]))?))?)?))$')
# to perform the actual date match
m = iso8601.match('2014-12-05T12:30:45.123456-05:30')
# prints a dict with all matched groups
print m.groupdict()
# output: {'full': '2014-12-05T12:30:45.123456-05:30', 'mday': '05', 'hour': '12', 'min': '30', 'sec': '45.123456', 'mon': '12', 'year': '2014'}
I've noticed that when I'm parsing timestamp with timezone information under python 3.5 project I'm getting timezone unaware datetime objects:
Python 2.7.12 (default, Sep 29 2016, 13:30:34)
[...]
In [1]: import ciso8601
In [2]: t = ciso8601.parse_datetime('2014-01-09T21:48:00.921000+05:30')
In [3]: t.tzinfo
Out[3]: pytz.FixedOffset(330)
Python 3.5.1 (default, Sep 19 2016, 10:16:17)
[...]
In [1]: import ciso8601
In [2]: t = ciso8601.parse_datetime('2014-01-09T21:48:00.921000+05:30')
In [3]: t.tzinfo
In [4]: type(t.tzinfo)
Out[4]: NoneType
Using ciso8601==1.0.2
in both cases. Tested on Fedora 24 with distro provided python binaries.
As part of my work on #55, I needed to get the version of ciso8601 programmatically.
This lead me to discover PEP 396, which defines the __version__
attribute for this purpose.
While the PEP is technically "differed", it seems that the majority of packages implement it.
Implement the __version__
attribute in ciso8601.
README mentions RFC3339 parsing, however latest release does not include this feature yet. It would be nice to cut a new release that includes it.
The Git ecosystem has moved away from the default branch name of master
, towards the name main
.
e.g. All new repos on GitHub/GitLab/Bitbucket now use main
as the default branch name for new repositories.
Change the default branch of ciso8601
to use main
.
git grep master
and update mentions of the outdated branch name in documentation and URLs.Developers with local clones will have to perform a one-time update of the local clones by running:
git branch -m master main
git fetch origin
git branch -u origin/main main
git symbolic-ref refs/remotes/origin/HEAD refs/remotes/origin/main
These commands are also shown to developers who visit the repo in the GitHub interface, so it doesn't require additional advertising work from our end.
Like in this lib: isodate
Lib python code if needed
Examples:
P1Y2M6DT20H46M20S
PT1H5M26S
PT9H55M
Should ideally have a breakdown for the latest stable Python versions (2.7, 3.6), and for 3.7.
I would like to be able to specify a specific format that a date/time must match to be considered valid, something like:
ciso.parse_datetime('2016-11-16T12:34:56.789', '%Y-%m-%dT%H:%M:%S.%f')
#or
ciso_parse_datetime('2016-11-16T12:34:56.789', ciso.DATE_TIME_WITH_MICROSECONDS)
Since this is a library for parsing ISO8601 date/times I think it would make sense to limit this to a strict set of formats (I do not want to be able to parse any arbitrary format).
This makes it easier to be strict on the format of date accepted for APIs etc.
See #18
We should probably do a better job at failing in https://github.com/closeio/ciso8601/blob/master/module.c#L245
I think right now it leaves (it's a global, so it's NULL by default)pytz_fixed_offset
and pytz_utc
uninitialized, which is bad.
In [1]: import ciso8601
In [2]: ciso8601.parse_datetime('20140200')
Out[2]: datetime.datetime(2014, 2, 1)
Expected the parse to fail, since there is no day 0 (in any month, let alone February).
Instead it succeeds because of this line.
Given that I want to use the pendulum timezone implementation within ciso8601
, I would like to create some mechanism for recognizing the contributions of @ sdispater.
Perhaps something similar to:
https://github.com/kentcdodds/all-contributors
When parsing unicode strings with non-ascii characters the ValueError is not built correctly. In CPython this manifests itself as an empty ValueError, whereas in PyPy3 it actually causes a segfault.
For example
from ciso8601 import parse_datetime
try:
parse_datetime("2019🐵01🐵01")
except ValueError as e:
assert e.args and "Invalid character" in e.args[0]
will fail with either a segfault or an assertion error depending on your interpreter.
In the real world this was seen with non-ascii dashes - e.g. for "2019—01—01"
Can't install ciso8601
ERROR: Command errored out with exit status 1:
command: /usr/local/bin/python -u -c 'import sys, setuptools, tokenize; sys.argv[0] = '"'"'/tmp/pip-install-u2k0mvob/ciso8601/setup.py'"'"'; __file__='"'"'/tmp/pip-install-u2k0mvob/ciso8601/setup.py'"'"';f=getattr(tokenize, '"'"'open'"'"', open)(__file__);code=f.read().replace('"'"'\r\n'"'"', '"'"'\n'"'"');f.close();exec(compile(code, __file__, '"'"'exec'"'"'))' bdist_wheel -d /tmp/pip-wheel-ey7cx4f6
cwd: /tmp/pip-install-u2k0mvob/ciso8601/
Complete output (15 lines):
running bdist_wheel
running build
running build_py
package init file 'ciso8601/__init__.py' not found (or not a regular file)
creating build
creating build/lib.linux-x86_64-3.8
creating build/lib.linux-x86_64-3.8/ciso8601
copying ciso8601/__init__.pyi -> build/lib.linux-x86_64-3.8/ciso8601
copying ciso8601/py.typed -> build/lib.linux-x86_64-3.8/ciso8601
running build_ext
building 'ciso8601' extension
creating build/temp.linux-x86_64-3.8
gcc -pthread -Wno-unused-result -Wsign-compare -DNDEBUG -g -fwrapv -O3 -Wall -fPIC -DCISO8601_VERSION=2.1.3 -I/usr/local/include/python3.8 -c module.c -o build/temp.linux-x86_64-3.8/module.o
unable to execute 'gcc': No such file or directory
error: command 'gcc' failed with exit status 1
----------------------------------------
ERROR: Failed building wheel for ciso8601
Try to install it in clean Docker python3.8 image, e.g. python:3.8-slim-buster
ISO 8601 allows for a special case of midnight: 24:00:00
.
For example 2007-04-05T24:00
is the same instant as 2007-04-06T00:00
But ciso8601 currently supports the latter:
In [1]: import ciso8601
In [2]: ciso8601.parse_datetime('2007-04-06T00:00')
Out[2]: datetime.datetime(2007, 4, 6, 0, 0)
In [3]: ciso8601.parse_datetime('2007-04-05T24:00')
Out[3]: None
Tested on ciso8601 version 1.0.7
Variable declaration should be wrapped in #ifdef for Python versions where it's not needed (I believe >= 3.2).
module.c: In function ‘PyInit_ciso8601’:
module.c:414:15: warning: unused variable ‘pytz’ [-Wunused-variable]
PyObject *pytz;
Also, should we trigger errors on compile warnings to catch these?
Nice job on the library guys. I'm not sure if this is an issue with pypy or with the library. If you pass in a bad string, this library crashes the interpreter entirely:
$ pypy
Python 2.7.9 (295ee98b69288471b0fcf2e0ede82ce5209eb90b, Jun 02 2015, 18:26:45)
[PyPy 2.6.0 with GCC 4.2.1 Compatible Apple LLVM 6.1.0 (clang-602.0.53)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>>> import ciso8601
>>>> ciso8601.parse_datetime_unaware('not-a-date')
pypy(36682,0x7fff7b7db300) malloc: *** error for object 0x1016df220: pointer being freed was not allocated
*** set a breakpoint in malloc_error_break to debug
Abort trap: 6
FWIW normal python 2.7.10 doesn't have the same problem:
$ python
Python 2.7.10 (default, Jul 22 2015, 21:18:21)
[GCC 4.2.1 Compatible Apple LLVM 6.1.0 (clang-602.0.53)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import ciso8601
>>> ciso8601.parse_datetime_unaware('not-a-date')
>>>
Thanks
Here is a flame graph of where the time is spent in ciso8601 v2.0.0
:
This is a 10 million calls to parse_datetime
with a timestamp with timezone information on Python 3.7.
Overall time: 1.14s
Action | C function | Time spent | Percentage |
---|---|---|---|
Converting the input Python string to C string | PyArg_ParseTuple |
0.24s | 21% |
Creating the timedelta for the timezone object | new_delta_ex |
0.34s | 30% |
Creating the timezone object for the datetime | new_timezone |
0.15s | 13% |
Creating the final datetime | new_datetime_ex |
0.25s | 22% |
Rest of computation | 0.16s | 14% |
If we were to cache the timezone objects as we created them, then subsequent parses with the same timezone information would save that time.
This eliminates the expensive call to new_delta_ex
, as well as the less expensive call to new_timezone
. These are 43% of the run time.
I assert that in most use cases, only a handlful of offsets are ever used, so the performance would be much better after the first few parses.
There are only ((1440 - 1) * 2) + 1 = 2879
valid offsets in ISO 8601 (that Python supports), so we can also bound the maximum amount of memory used.
Thanks for the great work on this library. I just upgraded some dateparsing code to use it and saw massive performance gains. I also noticed a minor bug -- the ciso_8601 module isn't correctly setting the "version" attribute:
# encoding: utf-8
# module ciso8601
# from /opt/pyre/lib/python3.5/site-packages/ciso8601.cpython-35m-x86_64-linux-gnu.so
# by generator 1.145
# no doc
# no imports
# Variables with simple values
__version__ = 'CISO8601_VERSION'
# functions
def parse_datetime(*args, **kwargs): # real signature unknown
""" Parse a ISO8601 date time string. """
pass
def parse_datetime_as_naive(*args, **kwargs): # real signature unknown
""" Parse a ISO8601 date time string, ignoring the time zone component. """
pass
def parse_rfc3339(*args, **kwargs): # real signature unknown
""" Parse an RFC 3339 date time string. """
pass
# no classes
# variables with complex values
__loader__ = None # (!) real value is ''
__spec__ = None # (!) real value is ''
I expect __version__
should equal 2.1.1
, not CISO8601_VERSION
. I peeked a bit into the C code and noticed this is set from there, using a macro defined in setup.py... I don't have much experience building python modules from C, but I'm happy to look into this if ya'll are jammed.
Thanks again for the great work.
ISO 8601-1:2019
changed the definition of what is a valid ISO 8601 timestamp.
For example, it explicitly disallowed the special case of 24:00
times.
Figure out how we want to handle the evolution of the specification.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.