mirror of
https://github.com/kennethreitz/maya.git
synced 2026-06-05 23:00:18 +00:00
Compare commits
86 Commits
Tafkas-master
...
v0.3.4
| Author | SHA1 | Date | |
|---|---|---|---|
| 0108ebe07e | |||
| a7d89be3c7 | |||
| 99ffb773bb | |||
| b3293f898e | |||
| 2d8015a13b | |||
| 9066ee862d | |||
| 5f362a8968 | |||
| 565fdd6a9e | |||
| 24063b5e1b | |||
| b57f4a6775 | |||
| 91e7f499e2 | |||
| be3a349b16 | |||
| f69a93b110 | |||
| 86586e733c | |||
| cd7b5b4aae | |||
| b70884a1ec | |||
| 773cdecab5 | |||
| ca865cd840 | |||
| 5cf40b2d2e | |||
| 93152fa7f4 | |||
| baa0660a9b | |||
| fd62815ce5 | |||
| c0092e74ae | |||
| 79d017fdcf | |||
| 7331d0d855 | |||
| 9c90c0534a | |||
| b9c501b0e4 | |||
| 3a71ff0174 | |||
| 43cc1d5946 | |||
| aecb643beb | |||
| fa966900e1 | |||
| 892e589ef2 | |||
| 0f795738c0 | |||
| b333489081 | |||
| 17a450eb5d | |||
| 8cd2158567 | |||
| 883b1b9b92 | |||
| 414df5f3f5 | |||
| 1694ed7cf8 | |||
| cbe9f6bae7 | |||
| 8bdd5c65fa | |||
| 4d96d06d70 | |||
| bbdb9b8762 | |||
| 28ecad81bd | |||
| c56c552184 | |||
| d5e4853886 | |||
| 28b3a849a9 | |||
| d872f29cfc | |||
| d8cbdede28 | |||
| c0f1bd709f | |||
| 8469e60d3c | |||
| 953f857940 | |||
| 6375143eac | |||
| c0fd845d4c | |||
| 0f38b99157 | |||
| 66a016ea84 | |||
| 6f1df92b8f | |||
| 51c4298ece | |||
| 74092289dd | |||
| f3f2793b50 | |||
| 251f535d67 | |||
| 98e9a2190a | |||
| c8dd4b9264 | |||
| a1b27e80d6 | |||
| 92f3b83b8b | |||
| 0f39ec6323 | |||
| 4d88eede9d | |||
| 971ecec9cf | |||
| ef471f8041 | |||
| 0fda49bdb9 | |||
| a8a18462fe | |||
| 82dc88c878 | |||
| e9a14e32da | |||
| 7b7f990a13 | |||
| 720617f062 | |||
| 5bf45dbfb7 | |||
| 488a25bcd8 | |||
| b2ac4f08a5 | |||
| 57ccc67721 | |||
| 7814ec2864 | |||
| f39c932039 | |||
| 96ff770071 | |||
| cd16ee94f0 | |||
| 7c68489682 | |||
| 93e163722b | |||
| b3ac13fcbf |
+1
-1
@@ -6,4 +6,4 @@ python:
|
||||
# command to install dependencies
|
||||
install: pip install pipenv; pipenv lock; pipenv install --dev
|
||||
# command to run tests
|
||||
script: pipenv run pytest
|
||||
script: pipenv run pytest tests/
|
||||
|
||||
@@ -21,3 +21,6 @@ In chronological order:
|
||||
- jerry2yu (`@jerry2yu <https://github.com/jerry2yu>`_)
|
||||
- Joshua Li <joshua.r.li.98@gmail.com> (`@JoshuaRLi <https://github.com/JoshuaRLi>`_)
|
||||
- Sébastien Eustace <sebastien@eustace.io> (`@sdispater <https://github.com/sdispater>`_)
|
||||
- Evan Mattiza <emattiza@gmail.com> (`@emattiza <https://github.com/emattiza>`_)
|
||||
- Dima Spivak <dima@spivak.ch> (`@dimaspivak <https://github.com/dimaspivak>`_)
|
||||
- Tom Barron <tusculum@gmail.com> (`@dtbarron <https://github.com/tbarron>`_)
|
||||
|
||||
@@ -1,7 +1,21 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2016 Kenneth Reitz
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
@@ -1,2 +1,4 @@
|
||||
tests:
|
||||
pytest test_maya.py
|
||||
pytest tests/
|
||||
docs:
|
||||
cd docs && make html
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
[dev-packages]
|
||||
pytest = "*"
|
||||
Sphinx = "*"
|
||||
|
||||
[packages]
|
||||
humanize = "*"
|
||||
pytz = "*"
|
||||
@@ -5,6 +9,3 @@ dateparser = "*"
|
||||
"ruamel.yaml" = "*"
|
||||
tzlocal = "*"
|
||||
pendulum = ">=1.0"
|
||||
|
||||
[dev-packages]
|
||||
pytest = "*"
|
||||
|
||||
Generated
+245
-22
@@ -1,11 +1,26 @@
|
||||
{
|
||||
"_meta": {
|
||||
"hash": {
|
||||
"sha256": "5617ff73ba51e60721267b24dc01e83f33d2a3692870b60e394b0f75ed2dc313"
|
||||
"sha256": "e7c76d32bf7d24c6e3637eb39049c1543ba59729fe50da193414bde84a120587"
|
||||
},
|
||||
"host-environment-markers": {
|
||||
"implementation_name": "cpython",
|
||||
"implementation_version": "3.6.1",
|
||||
"os_name": "posix",
|
||||
"platform_machine": "x86_64",
|
||||
"platform_python_implementation": "CPython",
|
||||
"platform_release": "17.3.0",
|
||||
"platform_system": "Darwin",
|
||||
"platform_version": "Darwin Kernel Version 17.3.0: Thu Nov 9 18:09:22 PST 2017; root:xnu-4570.31.3~1/RELEASE_X86_64",
|
||||
"python_full_version": "3.6.1",
|
||||
"python_version": "3.6",
|
||||
"sys_platform": "darwin"
|
||||
},
|
||||
"pipfile-spec": 6,
|
||||
"requires": {},
|
||||
"sources": [
|
||||
{
|
||||
"name": "pypi",
|
||||
"url": "https://pypi.python.org/simple",
|
||||
"verify_ssl": true
|
||||
}
|
||||
@@ -13,60 +28,268 @@
|
||||
},
|
||||
"default": {
|
||||
"dateparser": {
|
||||
"hashes": [
|
||||
"sha256:e2629d2f8361722c6047138ca085256c9f2cf5cc657fd66122aa0564afa4dc33",
|
||||
"sha256:f8c24317120b06f71691d28076764ec084a132be2a250a78fdf54f6b427cac95"
|
||||
],
|
||||
"version": "==0.6.0"
|
||||
},
|
||||
"humanize": {
|
||||
"hashes": [
|
||||
"sha256:a43f57115831ac7c70de098e6ac46ac13be00d69abbf60bdcac251344785bb19"
|
||||
],
|
||||
"version": "==0.5.1"
|
||||
},
|
||||
"pendulum": {
|
||||
"version": "==1.2.0"
|
||||
"hashes": [
|
||||
"sha256:9196f0aa4eec534aaf02b45c47dccc6f74a255ecdab6c772cb6bcea6b22790e4",
|
||||
"sha256:a34690d8d4fc8eab34ea2dd9a99482dbbf0b1f059fe25effe204dd59bceda069",
|
||||
"sha256:1577a44b1f4bbc942136bce654df24e31735e1ff6aaa37e0a6207abf13868be9",
|
||||
"sha256:f68f0f13498c9350ffc712765c4e0bdc824a4afd767d1a71933ff7be380bf75e",
|
||||
"sha256:76d6861664126fef4cbbdc6218ca09d81c4ed8da4c6df9637e0069f7d820f901",
|
||||
"sha256:327c89477e6ea0e240cd9f94c241747a534ac6f3e71c9b2f3298485ffc8939b2",
|
||||
"sha256:4f1675010fd934aea011642c33c0dd9bc6954d9be7032c7f9ccfea1ac8d752d7",
|
||||
"sha256:e996c34fb101c9c6d88a839c19af74d7c067b92ed3371274efcf4d4b6dc160a6"
|
||||
],
|
||||
"version": "==1.4.0"
|
||||
},
|
||||
"python-dateutil": {
|
||||
"version": "==2.6.0"
|
||||
"hashes": [
|
||||
"sha256:95511bae634d69bc7329ba55e646499a842bc4ec342ad54a8cdb65645a0aad3c",
|
||||
"sha256:891c38b2a02f5bb1be3e4793866c8df49c7d19baabf9c1bad62547e0b4866aca"
|
||||
],
|
||||
"version": "==2.6.1"
|
||||
},
|
||||
"pytz": {
|
||||
"version": "==2017.2"
|
||||
"hashes": [
|
||||
"sha256:80af0f3008046b9975242012a985f04c5df1f01eed4ec1633d56cc47a75a6a48",
|
||||
"sha256:feb2365914948b8620347784b6b6da356f31c9d03560259070b2f30cff3d469d",
|
||||
"sha256:59707844a9825589878236ff2f4e0dc9958511b7ffaae94dc615da07d4a68d33",
|
||||
"sha256:d0ef5ef55ed3d37854320d4926b04a4cb42a2e88f71da9ddfdacfde8e364f027",
|
||||
"sha256:c41c62827ce9cafacd6f2f7018e4f83a6f1986e87bfd000b8cfbd4ab5da95f1a",
|
||||
"sha256:8cc90340159b5d7ced6f2ba77694d946fc975b09f1a51d93f3ce3bb399396f94",
|
||||
"sha256:dd2e4ca6ce3785c8dd342d1853dd9052b19290d5bf66060846e5dc6b8d6667f7",
|
||||
"sha256:699d18a2a56f19ee5698ab1123bbcc1d269d061996aeb1eda6d89248d3542b82",
|
||||
"sha256:fae4cffc040921b8a2d60c6cf0b5d662c1190fe54d718271db4eb17d44a185b7"
|
||||
],
|
||||
"version": "==2017.3"
|
||||
},
|
||||
"pytzdata": {
|
||||
"version": "==2017.2"
|
||||
"hashes": [
|
||||
"sha256:cd5b72400a7378b3b45eef5929cbe97ed44c3368685c35c477e316ebaa7e1809",
|
||||
"sha256:e87376f2ee7cb89af5ddea5ed07ce3e98a55f891d07ae87d8c49e99f069423f2"
|
||||
],
|
||||
"version": "==2017.3.1"
|
||||
},
|
||||
"regex": {
|
||||
"version": "==2017.04.29"
|
||||
},
|
||||
"ruamel.ordereddict": {
|
||||
"version": "==0.4.9"
|
||||
"hashes": [
|
||||
"sha256:28a542117efd479cff110711c28f34cb40636f670d427dc42710b5183fbd92c4",
|
||||
"sha256:93064faef899911a7378443fcfb1f2e93e19706a324162fc71dd996c85b24f37",
|
||||
"sha256:9c4b23f8a68470522a0cdfbdcffbe2f61d7659b5d505cb7c1a729a6805345210",
|
||||
"sha256:45fed2f98e5ca0fc420ff31cbd9eccbee41e4d607569fddaba0faea36ef6043d",
|
||||
"sha256:079c656874ba6c2e3332df488d4eff33b94b4e260e3901dce1553cb4f1f36c73",
|
||||
"sha256:c1ef8f72944bef49261daaa83c7d77439f54f8deefefc0e2cf7144ac8b20ac1f",
|
||||
"sha256:26795107acb81bb07ef832832548834b03846eb046e5ba9a5917ee012c68c1e6",
|
||||
"sha256:3e2609e0e366b21c3db3d41159d99e7bd37e02caaba24bba77ec5cc594c62c4e",
|
||||
"sha256:801e054c1aa163545d29e186a1bea779437a19b49c4da9e11049624c2d2bfd31",
|
||||
"sha256:51306abdaac9e712b208066d284ddc7e3a332c77ad6054ba8d305d607609a328",
|
||||
"sha256:660990e223ef2f71cb78b4e106a9a023652a31fd305051a901b0f87171b69e24",
|
||||
"sha256:47230e1af3479810b1ef2bf23768b5195588a03eea6248b678d6893c48f58082",
|
||||
"sha256:5f15a27c24ed4ad2ed492abe80ddf27d35d63ef6c0d8878c915de6bf9f36c6f3",
|
||||
"sha256:67025161b70b0625749b1b89200da59fecc2fda9d1e46f9ef588f9a4af9fc48f",
|
||||
"sha256:139678fc013b75e486e580c39b4c52d085ed7362e400960f8be1711a414f16b5"
|
||||
],
|
||||
"version": "==2018.1.10"
|
||||
},
|
||||
"ruamel.yaml": {
|
||||
"version": "==0.14.12"
|
||||
"hashes": [
|
||||
"sha256:14d161558e3bf89e87d77c218098be22fa9a0d6d0bea40250fce525b1d0cbee2",
|
||||
"sha256:fcfc24a21594c071cc4588e84b7657a1f47ebcf6037c6c43fa15c4bbd3989ec2",
|
||||
"sha256:02babffd019911841ba01b76e23dfec7c9e9b2725503fb2698c4982fa1a6e835",
|
||||
"sha256:c0908896e34b617ead40552cab03c1769bdc43d1da02419160dc900c5dfddde2",
|
||||
"sha256:01e30ecb1b1c0ebf9fce814dc20dace402571517277799291202b61b22096c24",
|
||||
"sha256:b6c5d5f03ba78e3f27c7188a00c4e09b6a4507fe3154ba40a294e09cb30ee016",
|
||||
"sha256:9225c83952d28f302cfc23c3d9a6f8231bfd581476d7aff1e3c7de49eecb4ee9",
|
||||
"sha256:c41e04b526d0153c9246cfab87d7ddefdc9f165cb8886a8ec48ba7a2b73069f6",
|
||||
"sha256:6d05c5a5baf829c70916c226ef3200650846a7227de226bca8a59efaf88bb973",
|
||||
"sha256:e3bbfe0d294e08fdbb0cb05485435a2ceb4e168e98b5dc611f051c1864986b4b",
|
||||
"sha256:68c8f2986bcb91b6db1aea8698941769840c7257e951a9377048f7eff35be773",
|
||||
"sha256:072f6364a89972e8dc0afdce3335a709d5464dfeaa4f736d092a54574338b874",
|
||||
"sha256:5504398fc755a2b14c9983b2101161a8591a4b30812590cc1c365e7fcc117dfa",
|
||||
"sha256:e2d2715bf92156bec5fb42e92e95dac1c4d9904f8a3d4e2d0c438758fe9092d7",
|
||||
"sha256:6d7929b24e329d662fa43b657fddfee5260e2d35d0a543065cd755d4e17a9b2f",
|
||||
"sha256:f2d02a4af5a13b09d0b823cdd0317b54f3e0115e50b5ac4d9840c3a1b566817f",
|
||||
"sha256:8dc74821e4bb6b21fb1ab35964e159391d99ee44981d07d57bf96e2395f3ef75"
|
||||
],
|
||||
"version": "==0.15.35"
|
||||
},
|
||||
"six": {
|
||||
"version": "==1.10.0"
|
||||
"hashes": [
|
||||
"sha256:832dc0e10feb1aa2c68dcc57dbb658f1c7e65b9b61af69048abc87a2db00a0eb",
|
||||
"sha256:70e8a77beed4562e7f14fe23a786b54f6296e34344c23bc42f07b15018ff98e9"
|
||||
],
|
||||
"version": "==1.11.0"
|
||||
},
|
||||
"tzlocal": {
|
||||
"version": "==1.4"
|
||||
"hashes": [
|
||||
"sha256:4ebeb848845ac898da6519b9b31879cf13b6626f7184c496037b818e238f2c4e"
|
||||
],
|
||||
"version": "==1.5.1"
|
||||
}
|
||||
},
|
||||
"develop": {
|
||||
"appdirs": {
|
||||
"version": "==1.4.3"
|
||||
"alabaster": {
|
||||
"hashes": [
|
||||
"sha256:2eef172f44e8d301d25aff8068fddd65f767a3f04b5f15b0f4922f113aa1c732",
|
||||
"sha256:37cdcb9e9954ed60912ebc1ca12a9d12178c26637abdf124e3cde2341c257fe0"
|
||||
],
|
||||
"version": "==0.7.10"
|
||||
},
|
||||
"packaging": {
|
||||
"version": "==16.8"
|
||||
"attrs": {
|
||||
"hashes": [
|
||||
"sha256:a17a9573a6f475c99b551c0e0a812707ddda1ec9653bed04c13841404ed6f450",
|
||||
"sha256:1c7960ccfd6a005cd9f7ba884e6316b5e430a3f1a6c37c5f87d8b43f83b54ec9"
|
||||
],
|
||||
"version": "==17.4.0"
|
||||
},
|
||||
"babel": {
|
||||
"hashes": [
|
||||
"sha256:ad209a68d7162c4cff4b29cdebe3dec4cef75492df501b0049a9433c96ce6f80",
|
||||
"sha256:8ce4cb6fdd4393edd323227cba3a077bceb2a6ce5201c902c65e730046f41f14"
|
||||
],
|
||||
"version": "==2.5.3"
|
||||
},
|
||||
"certifi": {
|
||||
"hashes": [
|
||||
"sha256:14131608ad2fd56836d33a71ee60fa1c82bc9d2c8d98b7bdbc631fe1b3cd1296",
|
||||
"sha256:edbc3f203427eef571f79a7692bb160a2b0f7ccaa31953e99bd17e307cf63f7d"
|
||||
],
|
||||
"version": "==2018.1.18"
|
||||
},
|
||||
"chardet": {
|
||||
"hashes": [
|
||||
"sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691",
|
||||
"sha256:84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae"
|
||||
],
|
||||
"version": "==3.0.4"
|
||||
},
|
||||
"docutils": {
|
||||
"hashes": [
|
||||
"sha256:7a4bd47eaf6596e1295ecb11361139febe29b084a87bf005bf899f9a42edc3c6",
|
||||
"sha256:02aec4bd92ab067f6ff27a38a38a41173bf01bed8f89157768c1573f53e474a6",
|
||||
"sha256:51e64ef2ebfb29cae1faa133b3710143496eca21c530f3f71424d77687764274"
|
||||
],
|
||||
"version": "==0.14"
|
||||
},
|
||||
"idna": {
|
||||
"hashes": [
|
||||
"sha256:8c7309c718f94b3a625cb648ace320157ad16ff131ae0af362c9f21b80ef6ec4",
|
||||
"sha256:2c6a5de3089009e3da7c5dde64a141dbc8551d5b7f6cf4ed7c2568d0cc520a8f"
|
||||
],
|
||||
"version": "==2.6"
|
||||
},
|
||||
"imagesize": {
|
||||
"hashes": [
|
||||
"sha256:6ebdc9e0ad188f9d1b2cdd9bc59cbe42bf931875e829e7a595e6b3abdc05cdfb",
|
||||
"sha256:0ab2c62b87987e3252f89d30b7cedbec12a01af9274af9ffa48108f2c13c6062"
|
||||
],
|
||||
"version": "==0.7.1"
|
||||
},
|
||||
"jinja2": {
|
||||
"hashes": [
|
||||
"sha256:74c935a1b8bb9a3947c50a54766a969d4846290e1e788ea44c1392163723c3bd",
|
||||
"sha256:f84be1bb0040caca4cea721fcbbbbd61f9be9464ca236387158b0feea01914a4"
|
||||
],
|
||||
"version": "==2.10"
|
||||
},
|
||||
"markupsafe": {
|
||||
"hashes": [
|
||||
"sha256:a6be69091dac236ea9c6bc7d012beab42010fa914c459791d627dad4910eb665"
|
||||
],
|
||||
"version": "==1.0"
|
||||
},
|
||||
"pluggy": {
|
||||
"hashes": [
|
||||
"sha256:7f8ae7f5bdf75671a718d2daf0a64b7885f74510bcd98b1a0bb420eb9a9d0cff"
|
||||
],
|
||||
"version": "==0.6.0"
|
||||
},
|
||||
"py": {
|
||||
"version": "==1.4.33"
|
||||
"hashes": [
|
||||
"sha256:8cca5c229d225f8c1e3085be4fcf306090b00850fefad892f9d96c7b6e2f310f",
|
||||
"sha256:ca18943e28235417756316bfada6cd96b23ce60dd532642690dcfdaba988a76d"
|
||||
],
|
||||
"version": "==1.5.2"
|
||||
},
|
||||
"pyparsing": {
|
||||
"pygments": {
|
||||
"hashes": [
|
||||
"sha256:78f3f434bcc5d6ee09020f92ba487f95ba50f1e3ef83ae96b9d5ffa1bab25c5d",
|
||||
"sha256:dbae1046def0efb574852fab9e90209b23f556367b5a320c0bcb871c77c3e8cc"
|
||||
],
|
||||
"version": "==2.2.0"
|
||||
},
|
||||
"pytest": {
|
||||
"version": "==3.0.7"
|
||||
"hashes": [
|
||||
"sha256:b84878865558194630c6147f44bdaef27222a9f153bbd4a08908b16bf285e0b1",
|
||||
"sha256:53548280ede7818f4dc2ad96608b9f08ae2cc2ca3874f2ceb6f97e3583f25bc4"
|
||||
],
|
||||
"version": "==3.3.2"
|
||||
},
|
||||
"setuptools": {
|
||||
"version": "==35.0.2"
|
||||
"pytz": {
|
||||
"hashes": [
|
||||
"sha256:80af0f3008046b9975242012a985f04c5df1f01eed4ec1633d56cc47a75a6a48",
|
||||
"sha256:feb2365914948b8620347784b6b6da356f31c9d03560259070b2f30cff3d469d",
|
||||
"sha256:59707844a9825589878236ff2f4e0dc9958511b7ffaae94dc615da07d4a68d33",
|
||||
"sha256:d0ef5ef55ed3d37854320d4926b04a4cb42a2e88f71da9ddfdacfde8e364f027",
|
||||
"sha256:c41c62827ce9cafacd6f2f7018e4f83a6f1986e87bfd000b8cfbd4ab5da95f1a",
|
||||
"sha256:8cc90340159b5d7ced6f2ba77694d946fc975b09f1a51d93f3ce3bb399396f94",
|
||||
"sha256:dd2e4ca6ce3785c8dd342d1853dd9052b19290d5bf66060846e5dc6b8d6667f7",
|
||||
"sha256:699d18a2a56f19ee5698ab1123bbcc1d269d061996aeb1eda6d89248d3542b82",
|
||||
"sha256:fae4cffc040921b8a2d60c6cf0b5d662c1190fe54d718271db4eb17d44a185b7"
|
||||
],
|
||||
"version": "==2017.3"
|
||||
},
|
||||
"requests": {
|
||||
"hashes": [
|
||||
"sha256:6a1b267aa90cac58ac3a765d067950e7dbbf75b1da07e895d1f594193a40a38b",
|
||||
"sha256:9c443e7324ba5b85070c4a818ade28bfabedf16ea10206da1132edaa6dda237e"
|
||||
],
|
||||
"version": "==2.18.4"
|
||||
},
|
||||
"six": {
|
||||
"version": "==1.10.0"
|
||||
"hashes": [
|
||||
"sha256:832dc0e10feb1aa2c68dcc57dbb658f1c7e65b9b61af69048abc87a2db00a0eb",
|
||||
"sha256:70e8a77beed4562e7f14fe23a786b54f6296e34344c23bc42f07b15018ff98e9"
|
||||
],
|
||||
"version": "==1.11.0"
|
||||
},
|
||||
"snowballstemmer": {
|
||||
"hashes": [
|
||||
"sha256:9f3bcd3c401c3e862ec0ebe6d2c069ebc012ce142cce209c098ccb5b09136e89",
|
||||
"sha256:919f26a68b2c17a7634da993d91339e288964f93c274f1343e3bbbe2096e1128"
|
||||
],
|
||||
"version": "==1.2.1"
|
||||
},
|
||||
"sphinx": {
|
||||
"hashes": [
|
||||
"sha256:b8baed19394af85b21755c68c7ec4eac57e8a482ed89cd01cd5d5ff72200fe0f",
|
||||
"sha256:c39a6fa41bd3ec6fc10064329a664ed3a3ca2e27640a823dc520c682e4433cdb"
|
||||
],
|
||||
"version": "==1.6.6"
|
||||
},
|
||||
"sphinxcontrib-websupport": {
|
||||
"hashes": [
|
||||
"sha256:f4932e95869599b89bf4f80fc3989132d83c9faa5bf633e7b5e0c25dffb75da2",
|
||||
"sha256:7a85961326aa3a400cd4ad3c816d70ed6f7c740acd7ce5d78cd0a67825072eb9"
|
||||
],
|
||||
"version": "==1.0.1"
|
||||
},
|
||||
"urllib3": {
|
||||
"hashes": [
|
||||
"sha256:06330f386d6e4b195fbfc736b297f58c5a892e4440e54d294d7004e3a9bbea1b",
|
||||
"sha256:cc44da8e1145637334317feebd728bd869a35285b93cbb4cca2577da7e62db4f"
|
||||
],
|
||||
"version": "==1.22"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+17
-7
@@ -20,6 +20,8 @@ Datetimes should be interacted with via an API written for humans.
|
||||
|
||||
Maya is mostly built around the headaches and use-cases around parsing datetime data from websites.
|
||||
|
||||
.. image:: https://farm4.staticflickr.com/3702/33288285996_5b69d2b8f7_k_d.jpg
|
||||
|
||||
|
||||
☤ Basic Usage of Maya
|
||||
---------------------
|
||||
@@ -63,6 +65,15 @@ Behold, datetimes for humans!
|
||||
>>> rand_day = maya.when('2011-02-07', timezone='US/Eastern')
|
||||
<MayaDT epoch=1297036800.0>
|
||||
|
||||
# Maya speaks Python.
|
||||
>>> m = maya.MayaDT.from_datetime(datetime.utcnow())
|
||||
>>> print(m)
|
||||
Wed, 20 Sep 2017 17:24:32 GMT
|
||||
|
||||
>>> m = maya.MayaDT.from_struct(time.gmtime())
|
||||
>>> print(m)
|
||||
Wed, 20 Sep 2017 17:24:32 GMT
|
||||
|
||||
>>> rand_day.day
|
||||
7
|
||||
|
||||
@@ -74,13 +85,13 @@ Behold, datetimes for humans!
|
||||
UTC
|
||||
|
||||
# Range of hours in a day:
|
||||
>>> maya.interval(start=maya.now(), end=maya.now().add(days=1), interval=60*60)
|
||||
>>> maya.intervals(start=maya.now(), end=maya.now().add(days=1), interval=60*60)
|
||||
<generator object intervals at 0x105ba5820>
|
||||
|
||||
☤ Advanced Usage of Maya
|
||||
------------------------
|
||||
|
||||
In addition to timestamps, Maya also includes a wonderfuly powerful ``MayaInterval`` class, which represents a range of time (e.g. an event). With this class, you can perform a multitude of advanced calendar calculations with finese and ease.
|
||||
In addition to timestamps, Maya also includes a wonderfuly powerful ``MayaInterval`` class, which represents a range of time (e.g. an event). With this class, you can perform a multitude of advanced calendar calculations with finesse and ease.
|
||||
|
||||
For example:
|
||||
|
||||
@@ -94,8 +105,7 @@ For example:
|
||||
|
||||
>>> event = MayaInterval(start=event_start, end=event_end)
|
||||
|
||||
From here, there a a number of methods available to you, which you can use to compare this event to another event.
|
||||
|
||||
From here, there are a number of methods available to you, which you can use to compare this event to another event.
|
||||
|
||||
|
||||
|
||||
@@ -114,7 +124,7 @@ From here, there a a number of methods available to you, which you can use to co
|
||||
☤ What about Delorean, Arrow, & Pendulum?
|
||||
-----------------------------------------
|
||||
|
||||
All these project complement eachother, and are friends. Pendulum, for example, helps power Maya's parsing.
|
||||
All these project complement each other, and are friends. Pendulum, for example, helps power Maya's parsing.
|
||||
|
||||
Arrow, for example, is a fantastic library, but isn't what I wanted in a datetime library. In many ways, it's better than Maya for certain things. In some ways, in my opinion, it's not.
|
||||
|
||||
@@ -126,9 +136,9 @@ I think these projects complement each-other, personally. Maya is great for pars
|
||||
☤ Installing Maya
|
||||
-----------------
|
||||
|
||||
Installation is easy, with pip::
|
||||
Installation is easy, with `pipenv <http://pipenv.org/>`_::
|
||||
|
||||
$ pip install maya
|
||||
$ pipenv install maya
|
||||
|
||||
✨🍰✨
|
||||
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
# Minimal makefile for Sphinx documentation
|
||||
#
|
||||
|
||||
# You can set these variables from the command line.
|
||||
SPHINXOPTS =
|
||||
SPHINXBUILD = python -msphinx
|
||||
SPHINXPROJ = maya
|
||||
SOURCEDIR = source
|
||||
BUILDDIR = _build
|
||||
|
||||
# Put it first so that "make" without argument is like "make help".
|
||||
help:
|
||||
@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
|
||||
|
||||
.PHONY: help Makefile
|
||||
|
||||
# Catch-all target: route all unknown targets to Sphinx using the new
|
||||
# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
|
||||
%: Makefile
|
||||
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
|
||||
@@ -0,0 +1,36 @@
|
||||
@ECHO OFF
|
||||
|
||||
pushd %~dp0
|
||||
|
||||
REM Command file for Sphinx documentation
|
||||
|
||||
if "%SPHINXBUILD%" == "" (
|
||||
set SPHINXBUILD=python -msphinx
|
||||
)
|
||||
set SOURCEDIR=source
|
||||
set BUILDDIR=build
|
||||
set SPHINXPROJ=maya
|
||||
|
||||
if "%1" == "" goto help
|
||||
|
||||
%SPHINXBUILD% >NUL 2>NUL
|
||||
if errorlevel 9009 (
|
||||
echo.
|
||||
echo.The Sphinx module was not found. Make sure you have Sphinx installed,
|
||||
echo.then set the SPHINXBUILD environment variable to point to the full
|
||||
echo.path of the 'sphinx-build' executable. Alternatively you may add the
|
||||
echo.Sphinx directory to PATH.
|
||||
echo.
|
||||
echo.If you don't have Sphinx installed, grab it from
|
||||
echo.http://sphinx-doc.org/
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS%
|
||||
goto end
|
||||
|
||||
:help
|
||||
%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS%
|
||||
|
||||
:end
|
||||
popd
|
||||
@@ -0,0 +1,163 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# maya documentation build configuration file, created by
|
||||
# sphinx-quickstart on Sun May 28 15:46:10 2017.
|
||||
#
|
||||
# This file is execfile()d with the current directory set to its
|
||||
# containing dir.
|
||||
#
|
||||
# Note that not all possible configuration values are present in this
|
||||
# autogenerated file.
|
||||
#
|
||||
# All configuration values have a default; values that are commented out
|
||||
# serve to show the default.
|
||||
|
||||
# If extensions (or modules to document with autodoc) are in another directory,
|
||||
# add these directories to sys.path here. If the directory is relative to the
|
||||
# documentation root, use os.path.abspath to make it absolute, like shown here.
|
||||
#
|
||||
import os
|
||||
import sys
|
||||
# sys.path.insert(0, os.path.abspath('.'))
|
||||
sys.path.insert(0, os.path.abspath('..'))
|
||||
sys.path.insert(0, os.path.abspath('_themes'))
|
||||
|
||||
import maya
|
||||
|
||||
# -- General configuration ------------------------------------------------
|
||||
|
||||
# If your documentation needs a minimal Sphinx version, state it here.
|
||||
#
|
||||
# needs_sphinx = '1.0'
|
||||
|
||||
# Add any Sphinx extension module names here, as strings. They can be
|
||||
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
|
||||
# ones.
|
||||
extensions = ['sphinx.ext.autodoc',
|
||||
'sphinx.ext.todo',
|
||||
'sphinx.ext.coverage',
|
||||
'sphinx.ext.viewcode']
|
||||
|
||||
# Add any paths that contain templates here, relative to this directory.
|
||||
templates_path = ['_templates']
|
||||
|
||||
# The suffix(es) of source filenames.
|
||||
# You can specify multiple suffix as a list of string:
|
||||
#
|
||||
# source_suffix = ['.rst', '.md']
|
||||
source_suffix = '.rst'
|
||||
|
||||
# The master toctree document.
|
||||
master_doc = 'index'
|
||||
|
||||
# General information about the project.
|
||||
project = 'maya'
|
||||
copyright = '2017, Kenneth Reitz'
|
||||
author = 'Kenneth Reitz'
|
||||
|
||||
# The version info for the project you're documenting, acts as replacement for
|
||||
# |version| and |release|, also used in various other places throughout the
|
||||
# built documents.
|
||||
#
|
||||
# The short X.Y version.
|
||||
version = maya.__version__
|
||||
# The full version, including alpha/beta/rc tags.
|
||||
release = maya.__version__
|
||||
|
||||
# The language for content autogenerated by Sphinx. Refer to documentation
|
||||
# for a list of supported languages.
|
||||
#
|
||||
# This is also used if you do content translation via gettext catalogs.
|
||||
# Usually you set "language" from the command line for these cases.
|
||||
language = None
|
||||
|
||||
# List of patterns, relative to source directory, that match files and
|
||||
# directories to ignore when looking for source files.
|
||||
# This patterns also effect to html_static_path and html_extra_path
|
||||
exclude_patterns = []
|
||||
|
||||
# The name of the Pygments (syntax highlighting) style to use.
|
||||
pygments_style = 'sphinx'
|
||||
|
||||
# If true, `todo` and `todoList` produce output, else they produce nothing.
|
||||
todo_include_todos = True
|
||||
|
||||
|
||||
# -- Options for HTML output ----------------------------------------------
|
||||
|
||||
# The theme to use for HTML and HTML Help pages. See the documentation for
|
||||
# a list of builtin themes.
|
||||
#
|
||||
html_theme = 'alabaster'
|
||||
|
||||
# Theme options are theme-specific and customize the look and feel of a theme
|
||||
# further. For a list of options available for each theme, see the
|
||||
# documentation.
|
||||
#
|
||||
# html_theme_options = {}
|
||||
|
||||
# Add any paths that contain custom static files (such as style sheets) here,
|
||||
# relative to this directory. They are copied after the builtin static files,
|
||||
# so a file named "default.css" will overwrite the builtin "default.css".
|
||||
html_static_path = ['_static']
|
||||
|
||||
|
||||
# -- Options for HTMLHelp output ------------------------------------------
|
||||
|
||||
# Output file base name for HTML help builder.
|
||||
htmlhelp_basename = 'mayadoc'
|
||||
|
||||
|
||||
# -- Options for LaTeX output ---------------------------------------------
|
||||
|
||||
latex_elements = {
|
||||
# The paper size ('letterpaper' or 'a4paper').
|
||||
#
|
||||
# 'papersize': 'letterpaper',
|
||||
|
||||
# The font size ('10pt', '11pt' or '12pt').
|
||||
#
|
||||
# 'pointsize': '10pt',
|
||||
|
||||
# Additional stuff for the LaTeX preamble.
|
||||
#
|
||||
# 'preamble': '',
|
||||
|
||||
# Latex figure (float) alignment
|
||||
#
|
||||
# 'figure_align': 'htbp',
|
||||
}
|
||||
|
||||
# Grouping the document tree into LaTeX files. List of tuples
|
||||
# (source start file, target name, title,
|
||||
# author, documentclass [howto, manual, or own class]).
|
||||
latex_documents = [
|
||||
(master_doc, 'maya.tex', 'maya Documentation',
|
||||
'Kenneth Reitz', 'manual'),
|
||||
]
|
||||
|
||||
|
||||
# -- Options for manual page output ---------------------------------------
|
||||
|
||||
# One entry per manual page. List of tuples
|
||||
# (source start file, name, description, authors, manual section).
|
||||
man_pages = [
|
||||
(master_doc, 'maya', 'maya Documentation',
|
||||
[author], 1)
|
||||
]
|
||||
|
||||
|
||||
# -- Options for Texinfo output -------------------------------------------
|
||||
|
||||
# Grouping the document tree into Texinfo files. List of tuples
|
||||
# (source start file, target name, title, author,
|
||||
# dir menu entry, description, category)
|
||||
texinfo_documents = [
|
||||
(master_doc, 'maya', 'maya Documentation',
|
||||
author, 'maya', 'One line description of project.',
|
||||
'Miscellaneous'),
|
||||
]
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
.. maya documentation master file, created by
|
||||
sphinx-quickstart on Sun May 28 15:46:10 2017.
|
||||
You can adapt this file completely to your liking, but it should at least
|
||||
contain the root `toctree` directive.
|
||||
|
||||
Maya: Datetime for Humans
|
||||
================================
|
||||
Release v\ |version|. (:ref:`Installation <install>`)
|
||||
|
||||
.. image:: https://img.shields.io/pypi/v/maya.svg
|
||||
:target: https://pypi.python.org/pypi/maya
|
||||
|
||||
.. image:: https://travis-ci.org/kennethreitz/maya.svg?branch=master
|
||||
:target: https://travis-ci.org/kennethreitz/maya
|
||||
|
||||
.. image:: https://img.shields.io/badge/SayThanks-!-1EAEDB.svg
|
||||
:target: https://saythanks.io/to/kennethreitz
|
||||
|
||||
☤ Behold, datetimes for humans!
|
||||
-------------------------------
|
||||
.. code-block:: pycon
|
||||
|
||||
>>> now = maya.now()
|
||||
<MayaDT epoch=1481850660.9>
|
||||
|
||||
>>> tomorrow = maya.when('tomorrow')
|
||||
<MayaDT epoch=1481919067.23>
|
||||
|
||||
>>> tomorrow.slang_date()
|
||||
'tomorrow'
|
||||
|
||||
>>> tomorrow.slang_time()
|
||||
'23 hours from now'
|
||||
|
||||
# Also: MayaDT.from_iso8601(...)
|
||||
>>> tomorrow.iso8601()
|
||||
'2017-02-10T22:17:01.445418Z'
|
||||
|
||||
# Also: MayaDT.from_rfc2822(...)
|
||||
>>> tomorrow.rfc2822()
|
||||
'Fri, 10 Feb 2017 22:17:01 GMT'
|
||||
|
||||
# Also: MayaDT.from_rfc3339(...)
|
||||
>>> tomorrow.rfc3339()
|
||||
'2017-02-10T22:17:01.44Z'
|
||||
|
||||
>>> tomorrow.datetime()
|
||||
datetime.datetime(2016, 12, 16, 15, 11, 30, 263350, tzinfo=<UTC>)
|
||||
|
||||
# Automatically parse datetime strings and generate naive datetimes.
|
||||
>>> scraped = '2016-12-16 18:23:45.423992+00:00'
|
||||
>>> maya.parse(scraped).datetime(to_timezone='US/Eastern', naive=True)
|
||||
datetime.datetime(2016, 12, 16, 13, 23, 45, 423992)
|
||||
|
||||
>>> rand_day = maya.when('2011-02-07', timezone='US/Eastern')
|
||||
<MayaDT epoch=1297036800.0>
|
||||
|
||||
>>> rand_day.day
|
||||
7
|
||||
|
||||
>>> rand_day.add(days=10).day
|
||||
17
|
||||
|
||||
# Always.
|
||||
>>> rand_day.timezone
|
||||
UTC
|
||||
|
||||
# Range of hours in a day:
|
||||
>>> maya.interval(
|
||||
... start=maya.now(),
|
||||
... end=maya.now().add(days=1),
|
||||
... interval=60*60)
|
||||
<generator object intervals at 0x105ba5820>
|
||||
|
||||
|
||||
Table of Contents
|
||||
-----------------
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
user/install
|
||||
user/quickstart
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
.. _install:
|
||||
Installation
|
||||
=============
|
||||
|
||||
Pip Install Maya
|
||||
----------------
|
||||
|
||||
To install maya, simply use::
|
||||
$ pip install maya
|
||||
|
||||
Source Code
|
||||
-----------
|
||||
Maya is actively developed on `Github
|
||||
<https://github.com/kennethreitz/maya.git>`_
|
||||
|
||||
You can either clone the public repository::
|
||||
|
||||
$ git clone git://github.com/kennethreitz/maya.git
|
||||
|
||||
Or, download the `tarball <https://github.com/kennethreitz/maya/tarball/master>`_::
|
||||
|
||||
$ curl -OL https://github.com/kennethreitz/maya/tarball/master
|
||||
# optionally, zipball is also available (for Windows users).
|
||||
|
||||
Once you have a copy of the source, you can embed it in your own Python
|
||||
package, or install it into your site-packages easily::
|
||||
|
||||
$ python setup.py install
|
||||
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
.. _quickstart:
|
||||
Quickstart
|
||||
==========
|
||||
|
||||
.. module::maya
|
||||
|
||||
Ready for a simple datetime tool? This doc provides some tools to use in your
|
||||
busy workflow.
|
||||
|
||||
First, make sure that Maya is:
|
||||
|
||||
- :ref:`Installed <install>`
|
||||
- :ref:`Up to date <update>`
|
||||
|
||||
|
||||
Parse a Date
|
||||
------------
|
||||
Parsing a date from a string with Maya is 🍰!
|
||||
|
||||
First, you'll need to import maya::
|
||||
|
||||
>>> import maya
|
||||
|
||||
There are currently two ways to make sense of datetime:
|
||||
|
||||
- ``maya.parse``
|
||||
- ``maya.when``
|
||||
|
||||
A simple answer is that you should use parse on machine output, and when on human input.
|
||||
|
||||
Use as follows::
|
||||
|
||||
>>> recent_win = maya.parse('2016-11-02T20:00PM')
|
||||
>>> old_win = maya.when('October 14, 1908')
|
||||
>>> grandpas_date = maya.when('108 years ago')
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
.. _update:
|
||||
Community Updates
|
||||
=================
|
||||
|
||||
If you'd like to stay up to date on the community and development of Maya,
|
||||
there are several options:
|
||||
|
||||
|
||||
GitHub
|
||||
------
|
||||
|
||||
The best way to track the development of Maya is through
|
||||
`the GitHub repo <https://github.com/kennethreitz/Maya>`_.
|
||||
|
||||
Twitter
|
||||
-------
|
||||
|
||||
The author, Kenneth Reitz, often tweets about new features and releases of Maya.
|
||||
|
||||
Follow `@kennethreitz <https://twitter.com/kennethreitz>`_ for updates.
|
||||
|
||||
|
||||
|
||||
Release and Version History
|
||||
===========================
|
||||
|
||||
.. include:: ../../HISTORY.rst
|
||||
@@ -0,0 +1,2 @@
|
||||
from .core import *
|
||||
from .__version__ import __version__
|
||||
@@ -0,0 +1 @@
|
||||
__version__ = '0.3.4'
|
||||
+185
-90
@@ -19,7 +19,7 @@ import dateparser
|
||||
import pendulum
|
||||
from tzlocal import get_localzone
|
||||
|
||||
from compat import cmp, comparable
|
||||
from .compat import cmp, comparable
|
||||
|
||||
_EPOCH_START = (1970, 1, 1)
|
||||
|
||||
@@ -27,7 +27,7 @@ _EPOCH_START = (1970, 1, 1)
|
||||
def validate_class_type_arguments(operator):
|
||||
"""
|
||||
Decorator to validate all the arguments to function
|
||||
are of the type of calling class
|
||||
are of the type of calling class for passed operator
|
||||
"""
|
||||
|
||||
def inner(function):
|
||||
@@ -39,7 +39,33 @@ def validate_class_type_arguments(operator):
|
||||
return function(self, *args, **kwargs)
|
||||
|
||||
return wrapper
|
||||
return inner
|
||||
|
||||
|
||||
def validate_arguments_type_of_function(param_type=None):
|
||||
"""
|
||||
Decorator to validate the <type> of arguments in
|
||||
the calling function are of the `param_type` class.
|
||||
|
||||
if `param_type` is None, uses `param_type` as the class where it is used.
|
||||
|
||||
Note: Use this decorator on the functions of the class.
|
||||
"""
|
||||
def inner(function):
|
||||
def wrapper(self, *args, **kwargs):
|
||||
type_ = param_type or type(self)
|
||||
for arg in args + tuple(kwargs.values()):
|
||||
if not isinstance(arg, type_):
|
||||
raise TypeError(('Invalid Type: {}.{}() accepts only the '
|
||||
'arguments of type "<{}>"').format(
|
||||
type(self).__name__,
|
||||
function.__name__,
|
||||
type_.__name__,
|
||||
)
|
||||
)
|
||||
return function(self, *args, **kwargs)
|
||||
|
||||
return wrapper
|
||||
return inner
|
||||
|
||||
|
||||
@@ -66,45 +92,52 @@ class MayaDT(object):
|
||||
|
||||
@validate_class_type_arguments('!=')
|
||||
def __ne__(self, maya_dt):
|
||||
return self._epoch != maya_dt._epoch
|
||||
return int(self._epoch) != int(maya_dt._epoch)
|
||||
|
||||
@validate_class_type_arguments('<')
|
||||
def __lt__(self, maya_dt):
|
||||
return self._epoch < maya_dt._epoch
|
||||
return int(self._epoch) < int(maya_dt._epoch)
|
||||
|
||||
@validate_class_type_arguments('<=')
|
||||
def __le__(self, maya_dt):
|
||||
return self._epoch <= maya_dt._epoch
|
||||
return int(self._epoch) <= int(maya_dt._epoch)
|
||||
|
||||
@validate_class_type_arguments('>')
|
||||
def __gt__(self, maya_dt):
|
||||
return self._epoch > maya_dt._epoch
|
||||
return int(self._epoch) > int(maya_dt._epoch)
|
||||
|
||||
@validate_class_type_arguments('>=')
|
||||
def __ge__(self, maya_dt):
|
||||
return self._epoch >= maya_dt._epoch
|
||||
return int(self._epoch) >= int(maya_dt._epoch)
|
||||
|
||||
def __hash__(self):
|
||||
return hash(int(self.epoch))
|
||||
|
||||
def __add__(self, item):
|
||||
return self.add(seconds=seconds_or_timedelta(item).total_seconds())
|
||||
def __add__(self, duration):
|
||||
return self.add(seconds=_seconds_or_timedelta(duration).total_seconds())
|
||||
|
||||
def __radd__(self, item):
|
||||
return self + item
|
||||
def __radd__(self, duration):
|
||||
return self + duration
|
||||
|
||||
def __sub__(self, item):
|
||||
return self.subtract(
|
||||
seconds=seconds_or_timedelta(item).total_seconds())
|
||||
def __sub__(self, duration_or_date):
|
||||
if isinstance(duration_or_date, MayaDT):
|
||||
return self.subtract_date(dt=duration_or_date)
|
||||
else:
|
||||
return self.subtract(
|
||||
seconds=_seconds_or_timedelta(duration_or_date).total_seconds())
|
||||
|
||||
def add(self, **kwargs):
|
||||
""""Returns a new MayaDT object with the given offsets."""
|
||||
"""Returns a new MayaDT object with the given offsets."""
|
||||
return self.from_datetime(pendulum.instance(self.datetime()).add(**kwargs))
|
||||
|
||||
def subtract(self, **kwargs):
|
||||
""""Returns a new MayaDT object with the given offsets."""
|
||||
"""Returns a new MayaDT object with the given offsets."""
|
||||
return self.from_datetime(pendulum.instance(self.datetime()).subtract(**kwargs))
|
||||
|
||||
def subtract_date(self, **kwargs):
|
||||
"""Returns a timedelta object with the duration between the dates"""
|
||||
return timedelta(self.epoch - kwargs['dt'].epoch)
|
||||
|
||||
# Timezone Crap
|
||||
# -------------
|
||||
|
||||
@@ -121,7 +154,9 @@ class MayaDT(object):
|
||||
@property
|
||||
def local_timezone(self):
|
||||
"""Returns the name of the local timezone, for informational purposes."""
|
||||
return self._local_tz.zone
|
||||
if self._local_tz.zone in pytz.all_timezones:
|
||||
return self._local_tz.zone
|
||||
return self.timezone
|
||||
|
||||
@property
|
||||
def _local_tz(self):
|
||||
@@ -129,6 +164,7 @@ class MayaDT(object):
|
||||
return get_localzone()
|
||||
|
||||
@staticmethod
|
||||
@validate_arguments_type_of_function(Datetime)
|
||||
def __dt_to_epoch(dt):
|
||||
"""Converts a datetime into an epoch."""
|
||||
|
||||
@@ -143,24 +179,33 @@ class MayaDT(object):
|
||||
# ---------
|
||||
|
||||
@classmethod
|
||||
@validate_arguments_type_of_function(Datetime)
|
||||
def from_datetime(klass, dt):
|
||||
"""Returns MayaDT instance from datetime."""
|
||||
return klass(klass.__dt_to_epoch(dt))
|
||||
|
||||
@classmethod
|
||||
def from_iso8601(klass, string):
|
||||
@validate_arguments_type_of_function(time.struct_time)
|
||||
def from_struct(klass, struct, timezone=pytz.UTC):
|
||||
"""Returns MayaDT instance from a 9-tuple struct (assumed to be from gmtime())"""
|
||||
struct_time = time.mktime(struct) - utc_offset()
|
||||
dt = Datetime.fromtimestamp(struct_time, timezone)
|
||||
return klass(klass.__dt_to_epoch(dt))
|
||||
|
||||
@classmethod
|
||||
def from_iso8601(klass, iso8601_string):
|
||||
"""Returns MayaDT instance from iso8601 string."""
|
||||
return parse(string)
|
||||
return parse(iso8601_string)
|
||||
|
||||
@staticmethod
|
||||
def from_rfc2822(string):
|
||||
def from_rfc2822(rfc2822_string):
|
||||
"""Returns MayaDT instance from rfc2822 string."""
|
||||
return parse(string)
|
||||
return parse(rfc2822_string)
|
||||
|
||||
@staticmethod
|
||||
def from_rfc3339(string):
|
||||
def from_rfc3339(rfc3339_string):
|
||||
"""Returns MayaDT instance from rfc3339 string."""
|
||||
return parse(string)
|
||||
return parse(rfc3339_string)
|
||||
|
||||
# Exporters
|
||||
# ---------
|
||||
@@ -216,6 +261,10 @@ class MayaDT(object):
|
||||
@property
|
||||
def day(self):
|
||||
return self.datetime().day
|
||||
|
||||
@property
|
||||
def date(self):
|
||||
return self.datetime().date()
|
||||
|
||||
@property
|
||||
def week(self):
|
||||
@@ -244,7 +293,7 @@ class MayaDT(object):
|
||||
|
||||
@property
|
||||
def epoch(self):
|
||||
return self._epoch
|
||||
return int(self._epoch)
|
||||
|
||||
# Human Slang Extras
|
||||
# ------------------
|
||||
@@ -260,6 +309,16 @@ class MayaDT(object):
|
||||
return humanize.naturaltime(dt)
|
||||
|
||||
|
||||
def utc_offset():
|
||||
"""Returns the current local time offset from UTC accounting for DST """
|
||||
ts = time.localtime()
|
||||
if ts[-1]:
|
||||
offset = time.altzone
|
||||
else:
|
||||
offset = time.timezone
|
||||
return offset
|
||||
|
||||
|
||||
def to_utc_offset_naive(dt):
|
||||
if dt.tzinfo is None:
|
||||
return dt
|
||||
@@ -302,7 +361,8 @@ class MayaInterval(object):
|
||||
'Exactly 2 of start, end, and duration must be specified')
|
||||
|
||||
# Convert duration to timedelta if seconds were provided.
|
||||
duration = seconds_or_timedelta(duration)
|
||||
if duration:
|
||||
duration = _seconds_or_timedelta(duration)
|
||||
|
||||
if not start:
|
||||
start = end - duration
|
||||
@@ -321,7 +381,7 @@ class MayaInterval(object):
|
||||
|
||||
def iso8601(self):
|
||||
"""Returns an ISO 8601 representation of the MayaInterval."""
|
||||
return '{0}/{1}'.format(self.start.iso6801, self.end.iso8601)
|
||||
return '{0}/{1}'.format(self.start.iso8601(), self.end.iso8601())
|
||||
|
||||
@classmethod
|
||||
def from_iso8601(cls, s):
|
||||
@@ -340,16 +400,19 @@ class MayaInterval(object):
|
||||
# # Duration and end, such as "P1Y2M10DT2H30M/2008-05-11T15:30:00Z"
|
||||
raise NotImplementedError()
|
||||
|
||||
def __and__(self, i):
|
||||
return self.intersection(i)
|
||||
@validate_arguments_type_of_function()
|
||||
def __and__(self, maya_interval):
|
||||
return self.intersection(maya_interval)
|
||||
|
||||
def __or__(self, i):
|
||||
return self.combine(i)
|
||||
@validate_arguments_type_of_function()
|
||||
def __or__(self, maya_interval):
|
||||
return self.combine(maya_interval)
|
||||
|
||||
def __eq__(self, i):
|
||||
@validate_arguments_type_of_function()
|
||||
def __eq__(self, maya_interval):
|
||||
return (
|
||||
self.start == i.start and
|
||||
self.end == i.end
|
||||
self.start == maya_interval.start and
|
||||
self.end == maya_interval.end
|
||||
)
|
||||
|
||||
def __hash__(self):
|
||||
@@ -359,10 +422,11 @@ class MayaInterval(object):
|
||||
yield self.start
|
||||
yield self.end
|
||||
|
||||
def __cmp__(self, i):
|
||||
@validate_arguments_type_of_function()
|
||||
def __cmp__(self, maya_interval):
|
||||
return (
|
||||
cmp(self.start, i.start) or
|
||||
cmp(self.end, i.end)
|
||||
cmp(self.start, maya_interval.start) or
|
||||
cmp(self.end, maya_interval.end)
|
||||
)
|
||||
|
||||
@property
|
||||
@@ -377,45 +441,49 @@ class MayaInterval(object):
|
||||
def is_instant(self):
|
||||
return self.timedelta == timedelta(seconds=0)
|
||||
|
||||
def intersects(self, i):
|
||||
return self & i is not None
|
||||
def intersects(self, maya_interval):
|
||||
return self & maya_interval is not None
|
||||
|
||||
@property
|
||||
def midpoint(self):
|
||||
return self.start.add(seconds=(self.duration / 2))
|
||||
|
||||
def combine(self, i):
|
||||
@validate_arguments_type_of_function()
|
||||
def combine(self, maya_interval):
|
||||
"""Returns a combined list of timespans, merged together."""
|
||||
ii = sorted([self, i])
|
||||
if self & i or self.is_adjacent(i):
|
||||
interval_list = sorted([self, maya_interval])
|
||||
if self & maya_interval or self.is_adjacent(maya_interval):
|
||||
return [
|
||||
MayaInterval(
|
||||
ii[0].start,
|
||||
max(ii[0].end, ii[1].end),
|
||||
interval_list[0].start,
|
||||
max(interval_list[0].end, interval_list[1].end),
|
||||
),
|
||||
]
|
||||
return ii
|
||||
return interval_list
|
||||
|
||||
def subtract(self, i):
|
||||
""""Removes the given inerval."""
|
||||
if not self & i:
|
||||
@validate_arguments_type_of_function()
|
||||
def subtract(self, maya_interval):
|
||||
""""Removes the given interval."""
|
||||
if not self & maya_interval:
|
||||
return [self]
|
||||
elif i.contains(self):
|
||||
elif maya_interval.contains(self):
|
||||
return []
|
||||
|
||||
ii = []
|
||||
if self.start < i.start:
|
||||
ii.append(MayaInterval(self.start, i.start))
|
||||
if self.end > i.end:
|
||||
ii.append(MayaInterval(i.end, self.end))
|
||||
return ii
|
||||
interval_list = []
|
||||
if self.start < maya_interval.start:
|
||||
interval_list.append(MayaInterval(self.start, maya_interval.start))
|
||||
if self.end > maya_interval.end:
|
||||
interval_list.append(MayaInterval(maya_interval.end, self.end))
|
||||
return interval_list
|
||||
|
||||
def split(self, duration, include_remainder=True):
|
||||
|
||||
# Convert seconds to timedelta, if appropriate.
|
||||
duration = seconds_or_timedelta(duration)
|
||||
duration = _seconds_or_timedelta(duration)
|
||||
|
||||
if duration <= timedelta(seconds=0):
|
||||
raise ValueError('cannot call split with a non-positive timedelta')
|
||||
|
||||
assert duration > timedelta(seconds=0), 'cannot call split with a non-positive timedelta'
|
||||
start = self.start
|
||||
while start < self.end:
|
||||
if start + duration <= self.end:
|
||||
@@ -428,10 +496,13 @@ class MayaInterval(object):
|
||||
"""Returns a quanitzed interval."""
|
||||
|
||||
# Convert seconds to timedelta, if appropriate.
|
||||
duration = seconds_or_timedelta(duration)
|
||||
duration = _seconds_or_timedelta(duration)
|
||||
timezone = pytz.timezone(timezone)
|
||||
|
||||
assert duration > timedelta(seconds=0), 'cannot quantize by non-positive timedelta'
|
||||
|
||||
if duration <= timedelta(seconds=0):
|
||||
raise ValueError('cannot quantize by non-positive timedelta')
|
||||
|
||||
epoch = timezone.localize(Datetime(1970, 1, 1))
|
||||
seconds = int(duration.total_seconds())
|
||||
|
||||
@@ -454,39 +525,42 @@ class MayaInterval(object):
|
||||
end=MayaDT.from_datetime(epoch).add(seconds=end_seconds),
|
||||
)
|
||||
|
||||
def intersection(self, i):
|
||||
@validate_arguments_type_of_function()
|
||||
def intersection(self, maya_interval):
|
||||
"""Returns the intersection between two intervals."""
|
||||
|
||||
start = max(self.start, i.start)
|
||||
end = min(self.end, i.end)
|
||||
start = max(self.start, maya_interval.start)
|
||||
end = min(self.end, maya_interval.end)
|
||||
|
||||
either_instant = self.is_instant or i.is_instant
|
||||
either_instant = self.is_instant or maya_interval.is_instant
|
||||
instant_overlap = (
|
||||
self.start == i.start or
|
||||
self.start == maya_interval.start or
|
||||
start <= end
|
||||
)
|
||||
if (either_instant and instant_overlap) or (start < end):
|
||||
return MayaInterval(start, end)
|
||||
|
||||
def contains(self, i):
|
||||
@validate_arguments_type_of_function()
|
||||
def contains(self, maya_interval):
|
||||
return (
|
||||
self.start <= i.start and
|
||||
self.end >= i.end
|
||||
self.start <= maya_interval.start and
|
||||
self.end >= maya_interval.end
|
||||
)
|
||||
|
||||
def __contains__(self, item):
|
||||
if isinstance(item, MayaDT):
|
||||
return self.contains_dt(item)
|
||||
def __contains__(self, maya_dt):
|
||||
if isinstance(maya_dt, MayaDT):
|
||||
return self.contains_dt(maya_dt)
|
||||
|
||||
return self.contains(item)
|
||||
return self.contains(maya_dt)
|
||||
|
||||
def contains_dt(self, dt):
|
||||
return self.start <= dt < self.end
|
||||
|
||||
def is_adjacent(self, i):
|
||||
@validate_arguments_type_of_function()
|
||||
def is_adjacent(self, maya_interval):
|
||||
return (
|
||||
self.start == i.end or
|
||||
self.end == i.start
|
||||
self.start == maya_interval.end or
|
||||
self.end == maya_interval.start
|
||||
)
|
||||
|
||||
@property
|
||||
@@ -506,11 +580,11 @@ class MayaInterval(object):
|
||||
).replace(' ', '').strip('\r\n').replace('\n', '\r\n')
|
||||
|
||||
@staticmethod
|
||||
def flatten(ii):
|
||||
return functools.reduce(lambda reduced, i: (
|
||||
(reduced[:-1] + i.combine(reduced[-1]))
|
||||
if reduced else [i]
|
||||
), sorted(ii), [])
|
||||
def flatten(interval_list):
|
||||
return functools.reduce(lambda reduced, maya_interval: (
|
||||
(reduced[:-1] + maya_interval.combine(reduced[-1]))
|
||||
if reduced else [maya_interval]
|
||||
), sorted(interval_list), [])
|
||||
|
||||
@classmethod
|
||||
def from_datetime(cls, start_dt=None, end_dt=None, duration=None):
|
||||
@@ -525,7 +599,7 @@ def now():
|
||||
return MayaDT(epoch=epoch)
|
||||
|
||||
|
||||
def when(string, timezone='UTC'):
|
||||
def when(string, timezone='UTC', prefer_past=False):
|
||||
""""Returns a MayaDT instance for the human moment specified.
|
||||
|
||||
Powered by dateparser. Useful for scraping websites.
|
||||
@@ -536,10 +610,15 @@ def when(string, timezone='UTC'):
|
||||
Keyword Arguments:
|
||||
string -- string to be parsed
|
||||
timezone -- timezone referenced from (default: 'UTC')
|
||||
prefer_past -- prefer parsing ambiguous date as in the past
|
||||
|
||||
"""
|
||||
dt = dateparser.parse(string,
|
||||
settings={'TIMEZONE': timezone, 'RETURN_AS_TIMEZONE_AWARE': True, 'TO_TIMEZONE': 'UTC'})
|
||||
settings = {'TIMEZONE': timezone, 'RETURN_AS_TIMEZONE_AWARE': True, 'TO_TIMEZONE': 'UTC'}
|
||||
|
||||
if prefer_past:
|
||||
settings['PREFER_DATES_FROM'] = 'past'
|
||||
|
||||
dt = dateparser.parse(string, settings=settings)
|
||||
|
||||
if dt is None:
|
||||
raise ValueError('invalid datetime input specified.')
|
||||
@@ -547,31 +626,47 @@ def when(string, timezone='UTC'):
|
||||
return MayaDT.from_datetime(dt)
|
||||
|
||||
|
||||
def parse(string, day_first=False):
|
||||
def parse(string, timezone='UTC', day_first=False, year_first=True):
|
||||
""""Returns a MayaDT instance for the machine-produced moment specified.
|
||||
|
||||
Powered by pendulum. Accepts most known formats. Useful for working with data.
|
||||
|
||||
Keyword Arguments:
|
||||
string -- string to be parsed
|
||||
day_first -- if true, the first value (e.g. 01/05/2016) is parsed as day (default: False)
|
||||
timezone -- timezone referenced from (default: 'UTC')
|
||||
day_first -- if true, the first value (e.g. 01/05/2016) is parsed as day.
|
||||
if year_first is set to True, this distinguishes between YDM and YMD. (default: False)
|
||||
year_first -- if true, the first value (e.g. 2016/05/01) is parsed as year (default: True)
|
||||
"""
|
||||
dt = pendulum.parse(string, day_first=day_first)
|
||||
options = {}
|
||||
options['tz'] = timezone
|
||||
options['day_first'] = day_first
|
||||
options['year_first'] = year_first
|
||||
|
||||
dt = pendulum.parse(string, **options)
|
||||
return MayaDT.from_datetime(dt)
|
||||
|
||||
|
||||
def seconds_or_timedelta(s):
|
||||
# Convert seconds into timedelta.
|
||||
if isinstance(s, int):
|
||||
s = timedelta(seconds=s)
|
||||
def _seconds_or_timedelta(duration):
|
||||
"""Returns `datetime.timedelta` object for the passed duration.
|
||||
|
||||
return s
|
||||
Keyword Arguments:
|
||||
duration -- `datetime.timedelta` object or seconds in `int` format.
|
||||
"""
|
||||
if isinstance(duration, int):
|
||||
dt_timedelta = timedelta(seconds=duration)
|
||||
elif isinstance(duration, timedelta):
|
||||
dt_timedelta = duration
|
||||
else:
|
||||
raise TypeError('Expects argument as `datetime.timedelta` object '
|
||||
'or seconds in `int` format')
|
||||
return dt_timedelta
|
||||
|
||||
|
||||
def intervals(start, end, interval):
|
||||
"""Yields MayaDT objects between the start and end MayaDTs given, at a given interval (seconds or timedelta)."""
|
||||
|
||||
interval = seconds_or_timedelta(interval)
|
||||
interval = _seconds_or_timedelta(interval)
|
||||
|
||||
current_timestamp = start
|
||||
while current_timestamp.epoch < end.epoch:
|
||||
@@ -7,14 +7,8 @@ import codecs
|
||||
|
||||
from setuptools import setup
|
||||
|
||||
try:
|
||||
# Python 3
|
||||
from os import dirname
|
||||
except ImportError:
|
||||
# Python 2
|
||||
from os.path import dirname
|
||||
|
||||
here = os.path.abspath(dirname(__file__))
|
||||
here = os.path.abspath(os.path.dirname(__file__))
|
||||
|
||||
with codecs.open(os.path.join(here, 'README.rst'), encoding='utf-8') as f:
|
||||
long_description = '\n' + f.read()
|
||||
@@ -33,18 +27,38 @@ required = [
|
||||
'pendulum'
|
||||
]
|
||||
|
||||
packages = [
|
||||
'maya',
|
||||
]
|
||||
|
||||
# About dict to store version and package info
|
||||
about = dict()
|
||||
with codecs.open(os.path.join(here, 'maya', '__version__.py'), 'r', encoding='utf-8') as f:
|
||||
exec(f.read(), about)
|
||||
|
||||
setup(
|
||||
name='maya',
|
||||
version='0.3.1',
|
||||
version=about['__version__'],
|
||||
description='Datetimes for Humans.',
|
||||
long_description=long_description,
|
||||
author='Kenneth Reitz',
|
||||
author_email='me@kennethreitz.org',
|
||||
url='https://github.com/kennethreitz/maya',
|
||||
py_modules=['maya'],
|
||||
packages=packages,
|
||||
install_requires=required,
|
||||
license='MIT',
|
||||
classifiers=(
|
||||
|
||||
'Development Status :: 5 - Production/Stable',
|
||||
'Intended Audience :: Developers',
|
||||
'License :: OSI Approved :: MIT License',
|
||||
'Natural Language :: English',
|
||||
'Operating System :: OS Independent',
|
||||
'Programming Language :: Python :: 2',
|
||||
'Programming Language :: Python :: 2.7',
|
||||
'Programming Language :: Python :: 3',
|
||||
'Programming Language :: Python :: 3.6',
|
||||
'Programming Language :: Python :: Implementation',
|
||||
'Programming Language :: Python :: Implementation :: CPython',
|
||||
'Topic :: Software Development :: Libraries :: Python Modules'
|
||||
),
|
||||
)
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
import pytest
|
||||
import pytz
|
||||
import copy
|
||||
from datetime import timedelta
|
||||
import time
|
||||
from datetime import date, timedelta, datetime as Datetime
|
||||
|
||||
import maya
|
||||
from maya.core import _seconds_or_timedelta # import private function
|
||||
|
||||
|
||||
def test_rfc2822():
|
||||
@@ -63,6 +66,31 @@ def test_parse_iso8601():
|
||||
assert expected == d.iso8601()
|
||||
|
||||
|
||||
def test_struct():
|
||||
now = round(time.time())
|
||||
ts = time.gmtime(now)
|
||||
m = maya.MayaDT.from_struct(ts)
|
||||
dt = Datetime.fromtimestamp(now, pytz.UTC)
|
||||
assert m._epoch != None
|
||||
assert m.datetime() == dt
|
||||
|
||||
ts = time.localtime(now)
|
||||
m = maya.MayaDT.from_struct(ts)
|
||||
dt = Datetime.fromtimestamp(time.mktime(ts) - maya.core.utc_offset(), pytz.UTC)
|
||||
assert m._epoch != None
|
||||
assert m.datetime() == dt
|
||||
|
||||
|
||||
def test_issue_104():
|
||||
e = 1507756331
|
||||
t = Datetime.utcfromtimestamp(e)
|
||||
t = maya.MayaDT.from_datetime(t)
|
||||
assert str(t) == 'Wed, 11 Oct 2017 21:12:11 GMT'
|
||||
t = time.gmtime(e)
|
||||
t = maya.MayaDT.from_struct(t)
|
||||
assert str(t) == 'Wed, 11 Oct 2017 21:12:11 GMT'
|
||||
|
||||
|
||||
def test_human_when():
|
||||
r1 = maya.when('yesterday')
|
||||
r2 = maya.when('today')
|
||||
@@ -155,11 +183,39 @@ def test_parse():
|
||||
d = maya.parse('01/05/2016', day_first=True)
|
||||
assert format(d) == '2016-05-01 00:00:00+00:00'
|
||||
|
||||
d = maya.parse('2016/05/01', year_first=True, day_first=False)
|
||||
assert format(d) == '2016-05-01 00:00:00+00:00'
|
||||
|
||||
d = maya.parse('2016/01/05', year_first=True, day_first=True)
|
||||
assert format(d) == '2016-05-01 00:00:00+00:00'
|
||||
|
||||
d = maya.parse('01/05/2016', timezone='UTC')
|
||||
assert format(d) == '2016-01-05 00:00:00+00:00'
|
||||
|
||||
d = maya.parse('01/05/2016', timezone='US/Central')
|
||||
assert format(d) == '2016-01-05 06:00:00+00:00'
|
||||
|
||||
|
||||
def test_when_past():
|
||||
next_month = str(maya.now().add(months=1).month)
|
||||
this_year = maya.now().year
|
||||
last_year = this_year - 1
|
||||
|
||||
future_date = maya.when(next_month)
|
||||
past_date = maya.when(next_month, prefer_past=True)
|
||||
|
||||
assert future_date.year == this_year
|
||||
if next_month == '1':
|
||||
assert past_date.year == this_year
|
||||
else:
|
||||
assert past_date.year == last_year
|
||||
|
||||
|
||||
def test_datetime_to_timezone():
|
||||
dt = maya.when('2016-01-01').datetime(to_timezone='US/Eastern')
|
||||
assert dt.tzinfo.zone == 'US/Eastern'
|
||||
|
||||
|
||||
def test_rfc3339():
|
||||
mdt = maya.when('2016-01-01')
|
||||
out = mdt.rfc3339()
|
||||
@@ -204,6 +260,17 @@ def test_comparison_operations():
|
||||
with pytest.raises(TypeError):
|
||||
now >= 1
|
||||
|
||||
|
||||
def test_seconds_or_timedelta():
|
||||
# test for value in seconds
|
||||
assert _seconds_or_timedelta(1234) == timedelta(0, 1234)
|
||||
# test for value as `datetime.timedelta`
|
||||
assert _seconds_or_timedelta(timedelta(0, 1234)) == timedelta(0, 1234)
|
||||
# test for invalid value
|
||||
with pytest.raises(TypeError):
|
||||
_seconds_or_timedelta('invalid interval')
|
||||
|
||||
|
||||
def test_intervals():
|
||||
now = maya.now()
|
||||
tomorrow = now.add(days=1)
|
||||
@@ -227,3 +294,23 @@ def test_dunder_sub():
|
||||
now = maya.now()
|
||||
assert now - 1 == now.subtract(seconds=1)
|
||||
assert now - timedelta(seconds=1) == now.subtract(seconds=1)
|
||||
|
||||
|
||||
def test_mayaDT_sub():
|
||||
now = maya.now()
|
||||
then = now.add(days=1)
|
||||
assert then - now == timedelta(24*60*60)
|
||||
assert now - then == timedelta(-24*60*60)
|
||||
|
||||
|
||||
def test_core_local_timezone(monkeypatch):
|
||||
@property
|
||||
def mock_local_tz(self):
|
||||
class StaticTzInfo(object):
|
||||
zone = 'local'
|
||||
def __repr__(self):
|
||||
return "<StaticTzInfo 'local'>"
|
||||
return StaticTzInfo()
|
||||
monkeypatch.setattr(maya.MayaDT, '_local_tz', mock_local_tz)
|
||||
mdt = maya.MayaDT(0)
|
||||
assert mdt.local_timezone == 'UTC'
|
||||
@@ -5,7 +5,7 @@ import pytest
|
||||
import pytz
|
||||
|
||||
import maya
|
||||
from compat import cmp
|
||||
from maya.compat import cmp
|
||||
|
||||
Los_Angeles = pytz.timezone('America/Los_Angeles')
|
||||
New_York = pytz.timezone('America/New_York')
|
||||
@@ -111,6 +111,10 @@ def test_interval_intersection(
|
||||
else:
|
||||
assert (interval1 & interval2) is None
|
||||
|
||||
# check invalid argument
|
||||
with pytest.raises(TypeError):
|
||||
interval1 & 'invalid type'
|
||||
|
||||
|
||||
def test_interval_intersects():
|
||||
base = maya.MayaDT.from_datetime(datetime(2016, 1, 1))
|
||||
@@ -122,6 +126,10 @@ def test_interval_intersects():
|
||||
base.add(days=3),
|
||||
))
|
||||
|
||||
# check invalid argument
|
||||
with pytest.raises(TypeError):
|
||||
interval.intersects('invalid type')
|
||||
|
||||
|
||||
def test_and_operator():
|
||||
base = maya.MayaDT.from_datetime(datetime(2016, 1, 1))
|
||||
@@ -134,6 +142,10 @@ def test_and_operator():
|
||||
interval1.intersection(interval2)
|
||||
)
|
||||
|
||||
# check invalid argument
|
||||
with pytest.raises(TypeError):
|
||||
interval1.intersection('invalid type')
|
||||
|
||||
|
||||
def test_interval_eq_operator():
|
||||
start = maya.now()
|
||||
@@ -143,6 +155,13 @@ def test_interval_eq_operator():
|
||||
assert interval == maya.MayaInterval(start=start, end=end)
|
||||
assert interval != maya.MayaInterval(start=start, end=end.add(days=1))
|
||||
|
||||
# check invalid argument
|
||||
with pytest.raises(TypeError):
|
||||
interval == 'invalid type'
|
||||
|
||||
with pytest.raises(TypeError):
|
||||
interval != 'invalid type'
|
||||
|
||||
|
||||
def test_interval_timedelta():
|
||||
start = maya.now()
|
||||
@@ -189,6 +208,10 @@ def test_interval_contains(
|
||||
assert interval1.contains(interval2) is expected
|
||||
assert (interval2 in interval1) is expected
|
||||
|
||||
# check invalid argument
|
||||
with pytest.raises(TypeError):
|
||||
interval1.contains('invalid type')
|
||||
|
||||
|
||||
@pytest.mark.parametrize('start_doy,end_doy,dt_doy,expected', (
|
||||
(2, 4, 1, False),
|
||||
@@ -215,6 +238,10 @@ def test_interval_in_operator_maya_dt(
|
||||
|
||||
assert (dt in interval) is expected
|
||||
|
||||
# check invalid argument
|
||||
with pytest.raises(TypeError):
|
||||
'invalid type' in interval
|
||||
|
||||
|
||||
def test_interval_hash():
|
||||
start = maya.now()
|
||||
@@ -256,6 +283,10 @@ def test_interval_cmp(start1, end1, start2, end2, expected):
|
||||
)
|
||||
assert cmp(interval1, interval2) == expected
|
||||
|
||||
# check invalid argument
|
||||
with pytest.raises(TypeError):
|
||||
cmp(interval1, 'invalid type')
|
||||
|
||||
|
||||
@pytest.mark.parametrize('start1,end1,start2,end2,expected', [
|
||||
(1, 2, 2, 3, [(1, 3)]),
|
||||
@@ -286,6 +317,10 @@ def test_interval_combine(start1, end1, start2, end2, expected):
|
||||
assert interval1.combine(interval2) == expected_intervals
|
||||
assert interval2.combine(interval1) == expected_intervals
|
||||
|
||||
# check invalid argument
|
||||
with pytest.raises(TypeError):
|
||||
interval2.combine('invalid type')
|
||||
|
||||
|
||||
@pytest.mark.parametrize('start1,end1,start2,end2,expected', [
|
||||
(1, 2, 3, 4, [(1, 2)]),
|
||||
@@ -323,6 +358,10 @@ def test_interval_subtract(start1, end1, start2, end2, expected):
|
||||
|
||||
assert interval1.subtract(interval2) == expected_intervals
|
||||
|
||||
# check invalid argument
|
||||
with pytest.raises(TypeError):
|
||||
interval1.subtract('invalid type')
|
||||
|
||||
|
||||
@pytest.mark.parametrize('start1,end1,start2,end2,expected', [
|
||||
(1, 2, 2, 3, True),
|
||||
@@ -347,6 +386,10 @@ def test_interval_is_adjacent(start1, end1, start2, end2, expected):
|
||||
)
|
||||
assert interval1.is_adjacent(interval2) == expected
|
||||
|
||||
# check invalid argument
|
||||
with pytest.raises(TypeError):
|
||||
interval1.is_adjacent('invalid type')
|
||||
|
||||
|
||||
@pytest.mark.parametrize('start,end,delta,include_remainder,expected', [
|
||||
(0, 10, 5, False, [(0, 5), (5, 10)]),
|
||||
@@ -387,10 +430,10 @@ def test_interval_split_non_positive_delta():
|
||||
end = start.add(days=1)
|
||||
interval = maya.MayaInterval(start=start, end=end)
|
||||
|
||||
with pytest.raises(AssertionError):
|
||||
with pytest.raises(ValueError):
|
||||
list(interval.split(timedelta(seconds=0)))
|
||||
|
||||
with pytest.raises(AssertionError):
|
||||
with pytest.raises(ValueError):
|
||||
list(interval.split(timedelta(seconds=-10)))
|
||||
|
||||
|
||||
@@ -442,9 +485,9 @@ def test_quantize_invalid_delta():
|
||||
end = start.add(days=1)
|
||||
interval = maya.MayaInterval(start=start, end=end)
|
||||
|
||||
with pytest.raises(AssertionError):
|
||||
with pytest.raises(ValueError):
|
||||
interval.quantize(timedelta(minutes=0))
|
||||
with pytest.raises(AssertionError):
|
||||
with pytest.raises(ValueError):
|
||||
interval.quantize(timedelta(minutes=-1))
|
||||
|
||||
|
||||
@@ -539,3 +582,9 @@ def test_interval_from_datetime():
|
||||
)
|
||||
assert interval3.start == start
|
||||
assert interval3.end == end
|
||||
|
||||
|
||||
def test_interval_iso8601():
|
||||
start = maya.when('11-17-11 08:09:10')
|
||||
interval = maya.MayaInterval(start=start, duration=1)
|
||||
assert interval.iso8601() == '2011-11-17T08:09:10Z/2011-11-17T08:09:11Z'
|
||||
Reference in New Issue
Block a user