diff --git a/poetry.lock b/poetry.lock index 77c49a6..9d581ba 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 1.8.3 and should not be changed by hand. +# This file is automatically @generated by Poetry 2.1.1 and should not be changed by hand. [[package]] name = "anyio" @@ -6,6 +6,8 @@ version = "4.4.0" description = "High level compatibility layer for multiple asynchronous event loop implementations" optional = true python-versions = ">=3.8" +groups = ["main"] +markers = "extra == \"notion\"" files = [ {file = "anyio-4.4.0-py3-none-any.whl", hash = "sha256:c1b2d8f46a8a812513012e1107cb0e68c17159a7a594208005a57dc776e1bdc7"}, {file = "anyio-4.4.0.tar.gz", hash = "sha256:5aadc6a1bbb7cdb0bede386cac5e2940f5e2ff3aa20277e991cf028e0585ce94"}, @@ -19,7 +21,7 @@ typing-extensions = {version = ">=4.1", markers = "python_version < \"3.11\""} [package.extras] doc = ["Sphinx (>=7)", "packaging", "sphinx-autodoc-typehints (>=1.2.0)", "sphinx-rtd-theme"] -test = ["anyio[trio]", "coverage[toml] (>=7)", "exceptiongroup (>=1.2.0)", "hypothesis (>=4.0)", "psutil (>=5.9)", "pytest (>=7.0)", "pytest-mock (>=3.6.1)", "trustme", "uvloop (>=0.17)"] +test = ["anyio[trio]", "coverage[toml] (>=7)", "exceptiongroup (>=1.2.0)", "hypothesis (>=4.0)", "psutil (>=5.9)", "pytest (>=7.0)", "pytest-mock (>=3.6.1)", "trustme", "uvloop (>=0.17) ; platform_python_implementation == \"CPython\" and platform_system != \"Windows\""] trio = ["trio (>=0.23)"] [[package]] @@ -28,6 +30,8 @@ version = "1.0.0" description = "Asana API client" optional = true python-versions = "*" +groups = ["main"] +markers = "extra == \"asana\"" files = [ {file = "asana-1.0.0-py2.py3-none-any.whl", hash = "sha256:ea970c1e2bf67c6cd5a801173a00a070aec544218eec87e083e180397d032904"}, {file = "asana-1.0.0.tar.gz", hash = "sha256:dd4c75bb6d8b7d1cfdba24bd424d9927970676e6afa93ed2a062cd88a612907f"}, @@ -44,6 +48,7 @@ version = "2.15.8" description = "An abstract syntax tree for Python with inference support." optional = false python-versions = ">=3.7.2" +groups = ["dev"] files = [ {file = "astroid-2.15.8-py3-none-any.whl", hash = "sha256:1aa149fc5c6589e3d0ece885b4491acd80af4f087baafa3fb5203b113e68cd3c"}, {file = "astroid-2.15.8.tar.gz", hash = "sha256:6c107453dffee9055899705de3c9ead36e74119cee151e5a9aaf7f0b0e020a6a"}, @@ -63,18 +68,19 @@ version = "24.2.0" description = "Classes Without Boilerplate" optional = false python-versions = ">=3.7" +groups = ["dev"] files = [ {file = "attrs-24.2.0-py3-none-any.whl", hash = "sha256:81921eb96de3191c8258c199618104dd27ac608d9366f5e35d011eae1867ede2"}, {file = "attrs-24.2.0.tar.gz", hash = "sha256:5cfb1b9148b5b086569baec03f20d7b6bf3bcacc9a42bebf87ffaaca362f6346"}, ] [package.extras] -benchmark = ["cloudpickle", "hypothesis", "mypy (>=1.11.1)", "pympler", "pytest (>=4.3.0)", "pytest-codspeed", "pytest-mypy-plugins", "pytest-xdist[psutil]"] -cov = ["cloudpickle", "coverage[toml] (>=5.3)", "hypothesis", "mypy (>=1.11.1)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"] -dev = ["cloudpickle", "hypothesis", "mypy (>=1.11.1)", "pre-commit", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"] +benchmark = ["cloudpickle ; platform_python_implementation == \"CPython\"", "hypothesis", "mypy (>=1.11.1) ; platform_python_implementation == \"CPython\" and python_version >= \"3.9\"", "pympler", "pytest (>=4.3.0)", "pytest-codspeed", "pytest-mypy-plugins ; platform_python_implementation == \"CPython\" and python_version >= \"3.9\" and python_version < \"3.13\"", "pytest-xdist[psutil]"] +cov = ["cloudpickle ; platform_python_implementation == \"CPython\"", "coverage[toml] (>=5.3)", "hypothesis", "mypy (>=1.11.1) ; platform_python_implementation == \"CPython\" and python_version >= \"3.9\"", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins ; platform_python_implementation == \"CPython\" and python_version >= \"3.9\" and python_version < \"3.13\"", "pytest-xdist[psutil]"] +dev = ["cloudpickle ; platform_python_implementation == \"CPython\"", "hypothesis", "mypy (>=1.11.1) ; platform_python_implementation == \"CPython\" and python_version >= \"3.9\"", "pre-commit", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins ; platform_python_implementation == \"CPython\" and python_version >= \"3.9\" and python_version < \"3.13\"", "pytest-xdist[psutil]"] docs = ["cogapp", "furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-towncrier", "towncrier (<24.7)"] -tests = ["cloudpickle", "hypothesis", "mypy (>=1.11.1)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"] -tests-mypy = ["mypy (>=1.11.1)", "pytest-mypy-plugins"] +tests = ["cloudpickle ; platform_python_implementation == \"CPython\"", "hypothesis", "mypy (>=1.11.1) ; platform_python_implementation == \"CPython\" and python_version >= \"3.9\"", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins ; platform_python_implementation == \"CPython\" and python_version >= \"3.9\" and python_version < \"3.13\"", "pytest-xdist[psutil]"] +tests-mypy = ["mypy (>=1.11.1) ; platform_python_implementation == \"CPython\" and python_version >= \"3.9\"", "pytest-mypy-plugins ; platform_python_implementation == \"CPython\" and python_version >= \"3.9\" and python_version < \"3.13\""] [[package]] name = "backports-zoneinfo" @@ -82,6 +88,8 @@ version = "0.2.1" description = "Backport of the standard library zoneinfo module" optional = true python-versions = ">=3.6" +groups = ["main"] +markers = "extra == \"caldav\" and python_version < \"3.9\"" files = [ {file = "backports.zoneinfo-0.2.1-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:da6013fd84a690242c310d77ddb8441a559e9cb3d3d59ebac9aca1a57b2e18bc"}, {file = "backports.zoneinfo-0.2.1-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:89a48c0d158a3cc3f654da4c2de1ceba85263fafb861b98b59040a5086259722"}, @@ -110,6 +118,7 @@ version = "0.21.4" description = "The bidirectional mapping library for Python." optional = false python-versions = ">=3.6" +groups = ["main"] files = [ {file = "bidict-0.21.4-py3-none-any.whl", hash = "sha256:3ac67daa353ecf853a1df9d3e924f005e729227a60a8dbada31a4c31aba7f654"}, {file = "bidict-0.21.4.tar.gz", hash = "sha256:42c84ffbe6f8de898af6073b4be9ea7ccedcd78d3474aa844c54e49d5a079f6f"}, @@ -121,6 +130,7 @@ version = "22.3.0" description = "The uncompromising code formatter." optional = false python-versions = ">=3.6.2" +groups = ["dev"] files = [ {file = "black-22.3.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:2497f9c2386572e28921fa8bec7be3e51de6801f7459dffd6e62492531c47e09"}, {file = "black-22.3.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5795a0375eb87bfe902e80e0c8cfaedf8af4d49694d69161e5bd3206c18618bb"}, @@ -167,6 +177,7 @@ version = "0.1.12" description = "Bergercookie's Useful Bits Of Python" optional = false python-versions = ">=3.8,<4.0" +groups = ["main"] files = [ {file = "bubop-0.1.12-py3-none-any.whl", hash = "sha256:090a13a588e6daaed28fef1d4ca687c2d6cae01b6c55e9adf838253d42d2fc2a"}, {file = "bubop-0.1.12.tar.gz", hash = "sha256:8becf500f85beeb816d6ffb3ce61f359ab9c4e73007c2f4d4224a522e333508b"}, @@ -185,10 +196,12 @@ version = "5.4.0" description = "Extensible memoizing collections and decorators" optional = false python-versions = ">=3.7" +groups = ["main", "dev"] files = [ {file = "cachetools-5.4.0-py3-none-any.whl", hash = "sha256:3ae3b49a3d5e28a77a0be2b37dbcb89005058959cb2323858c2657c4a8cab474"}, {file = "cachetools-5.4.0.tar.gz", hash = "sha256:b8adc2e7c07f105ced7bc56dbb6dfbe7c4a00acce20e2227b3f355be89bc6827"}, ] +markers = {main = "extra == \"google\""} [[package]] name = "caldav" @@ -196,6 +209,8 @@ version = "0.11.0" description = "CalDAV (RFC4791) client library" optional = true python-versions = "*" +groups = ["main"] +markers = "extra == \"caldav\"" files = [ {file = "caldav-0.11.0-py3-none-any.whl", hash = "sha256:689d632debce4c26aa990e4f4192813cfd0c2d6cc61fdd3e140fa6b545a614d5"}, {file = "caldav-0.11.0.tar.gz", hash = "sha256:00426ebb02f2328e43932216d1846ea9a12f8d715ada12bee4b39dc584d90b18"}, @@ -220,10 +235,12 @@ version = "2024.7.4" description = "Python package for providing Mozilla's CA Bundle." optional = false python-versions = ">=3.6" +groups = ["main", "dev"] files = [ {file = "certifi-2024.7.4-py3-none-any.whl", hash = "sha256:c198e21b1289c2ab85ee4e67bb4b4ef3ead0892059901a8d5b622f24a1101e90"}, {file = "certifi-2024.7.4.tar.gz", hash = "sha256:5a1e7645bc0ec61a09e26c36f6106dd4cf40c6db3a1fb6352b0244e7fb057c7b"}, ] +markers = {main = "(python_full_version != \"3.12.0\" or extra == \"google\" or extra == \"asana\" or extra == \"caldav\" or extra == \"notion\") and (extra == \"gkeep\" or extra == \"google\" or extra == \"asana\" or extra == \"caldav\" or extra == \"notion\")"} [[package]] name = "cffi" @@ -231,6 +248,8 @@ version = "1.17.0" description = "Foreign Function Interface for Python calling C code." optional = true python-versions = ">=3.8" +groups = ["main"] +markers = "extra == \"fs\"" files = [ {file = "cffi-1.17.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:f9338cc05451f1942d0d8203ec2c346c830f8e86469903d5126c1f0a13a2bcbb"}, {file = "cffi-1.17.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a0ce71725cacc9ebf839630772b07eeec220cbb5f03be1399e0457a1464f8e1a"}, @@ -310,6 +329,7 @@ version = "3.4.0" description = "Validate configuration and produce human readable error messages." optional = false python-versions = ">=3.8" +groups = ["dev"] files = [ {file = "cfgv-3.4.0-py2.py3-none-any.whl", hash = "sha256:b7265b1f29fd3316bfcd2b330d63d024f2bfd8bcb8b0272f8e19a504856c48f9"}, {file = "cfgv-3.4.0.tar.gz", hash = "sha256:e52591d4c5f5dead8e0f673fb16db7949d2cfb3f7da4582893288f0ded8fe560"}, @@ -321,10 +341,12 @@ version = "3.0.4" description = "Universal encoding detector for Python 2 and 3" optional = false python-versions = "*" +groups = ["main", "dev"] files = [ {file = "chardet-3.0.4-py2.py3-none-any.whl", hash = "sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691"}, {file = "chardet-3.0.4.tar.gz", hash = "sha256:84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae"}, ] +markers = {main = "python_version <= \"3.11\" and (extra == \"gkeep\" or extra == \"google\" or extra == \"asana\" or extra == \"caldav\")", dev = "python_version <= \"3.11\""} [[package]] name = "charset-normalizer" @@ -332,6 +354,7 @@ version = "3.3.2" description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." optional = false python-versions = ">=3.7.0" +groups = ["main", "dev"] files = [ {file = "charset-normalizer-3.3.2.tar.gz", hash = "sha256:f30c3cb33b24454a82faecaf01b19c18562b1e89558fb6c56de4d9118a032fd5"}, {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:25baf083bf6f6b341f4121c2f3c548875ee6f5339300e08be3f2b2ba1721cdd3"}, @@ -424,6 +447,7 @@ files = [ {file = "charset_normalizer-3.3.2-cp39-cp39-win_amd64.whl", hash = "sha256:b01b88d45a6fcb69667cd6d2f7a9aeb4bf53760d7fc536bf679ec94fe9f3ff3d"}, {file = "charset_normalizer-3.3.2-py3-none-any.whl", hash = "sha256:3e4d1f6587322d2788836a99c69062fbb091331ec940e02d12d179c1d53e25fc"}, ] +markers = {main = "python_full_version >= \"3.12.0\" and (python_full_version > \"3.12.0\" or extra == \"google\" or extra == \"asana\" or extra == \"caldav\") and (extra == \"gkeep\" or extra == \"google\" or extra == \"asana\" or extra == \"caldav\")", dev = "python_full_version >= \"3.12.0\""} [[package]] name = "check-jsonschema" @@ -431,6 +455,7 @@ version = "0.14.3" description = "A jsonschema CLI and pre-commit hook" optional = false python-versions = ">=3.7" +groups = ["dev"] files = [ {file = "check-jsonschema-0.14.3.tar.gz", hash = "sha256:38bb6f7771fe1b8c521df09b496846934569c5617c7ffae502f2edd2e5a53989"}, {file = "check_jsonschema-0.14.3-py3-none-any.whl", hash = "sha256:9fd6603266bea1534ea9d672e1568a81672686d15229713a05776e29556a5e26"}, @@ -452,6 +477,7 @@ version = "8.1.7" description = "Composable command line interface toolkit" optional = false python-versions = ">=3.7" +groups = ["main", "dev"] files = [ {file = "click-8.1.7-py3-none-any.whl", hash = "sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28"}, {file = "click-8.1.7.tar.gz", hash = "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de"}, @@ -466,6 +492,8 @@ version = "0.4.6" description = "Cross-platform colored terminal text." optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" +groups = ["main", "dev"] +markers = "platform_system == \"Windows\" or sys_platform == \"win32\"" files = [ {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, @@ -477,6 +505,7 @@ version = "6.5.0" description = "Code coverage measurement for Python" optional = false python-versions = ">=3.7" +groups = ["dev"] files = [ {file = "coverage-6.5.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ef8674b0ee8cc11e2d574e3e2998aea5df5ab242e012286824ea3c6970580e53"}, {file = "coverage-6.5.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:784f53ebc9f3fd0e2a3f6a78b2be1bd1f5575d7863e10c6e12504f240fd06660"}, @@ -534,7 +563,7 @@ files = [ tomli = {version = "*", optional = true, markers = "python_full_version <= \"3.11.0a6\" and extra == \"toml\""} [package.extras] -toml = ["tomli"] +toml = ["tomli ; python_full_version <= \"3.11.0a6\""] [[package]] name = "coveralls" @@ -542,6 +571,7 @@ version = "3.3.1" description = "Show coverage stats online via coveralls.io" optional = false python-versions = ">= 3.5" +groups = ["dev"] files = [ {file = "coveralls-3.3.1-py2.py3-none-any.whl", hash = "sha256:f42015f31d386b351d4226389b387ae173207058832fbf5c8ec4b40e27b16026"}, {file = "coveralls-3.3.1.tar.gz", hash = "sha256:b32a8bb5d2df585207c119d6c01567b81fba690c9c10a753bfe27a335bfc43ea"}, @@ -561,6 +591,7 @@ version = "0.3.8" description = "serialize all of Python" optional = false python-versions = ">=3.8" +groups = ["dev"] files = [ {file = "dill-0.3.8-py3-none-any.whl", hash = "sha256:c36ca9ffb54365bdd2f8eb3eff7d2a21237f8452b57ace88b1ac615b7e815bd7"}, {file = "dill-0.3.8.tar.gz", hash = "sha256:3ebe3c479ad625c4553aca177444d89b486b1d84982eeacded644afc0cf797ca"}, @@ -576,6 +607,7 @@ version = "0.3.8" description = "Distribution utilities" optional = false python-versions = "*" +groups = ["dev"] files = [ {file = "distlib-0.3.8-py2.py3-none-any.whl", hash = "sha256:034db59a0b96f8ca18035f36290806a9a6e6bd9d1ff91e45a7f172eb17e51784"}, {file = "distlib-0.3.8.tar.gz", hash = "sha256:1530ea13e350031b6312d8580ddb6b27a104275a31106523b8f123787f494f64"}, @@ -587,6 +619,7 @@ version = "0.6.2" description = "Pythonic argument parser, that will make you smile" optional = false python-versions = "*" +groups = ["dev"] files = [ {file = "docopt-0.6.2.tar.gz", hash = "sha256:49b3a825280bd66b3aa83585ef59c4a8c82f2c8a522dbe754a8bc8d08c85c491"}, ] @@ -597,10 +630,12 @@ version = "1.2.2" description = "Backport of PEP 654 (exception groups)" optional = false python-versions = ">=3.7" +groups = ["main", "dev"] files = [ {file = "exceptiongroup-1.2.2-py3-none-any.whl", hash = "sha256:3111b9d131c238bec2f8f516e123e14ba243563fb135d3fe885990585aa7795b"}, {file = "exceptiongroup-1.2.2.tar.gz", hash = "sha256:47c2edf7c6738fafb49fd34290706d1a1a2f4d1c6df275526b62cbb4aa5393cc"}, ] +markers = {main = "python_version < \"3.11\" and extra == \"notion\"", dev = "python_version < \"3.11\""} [package.extras] test = ["pytest (>=6)"] @@ -611,6 +646,7 @@ version = "3.15.4" description = "A platform independent file lock." optional = false python-versions = ">=3.8" +groups = ["dev"] files = [ {file = "filelock-3.15.4-py3-none-any.whl", hash = "sha256:6ca1fffae96225dab4c6eaf1c4f4f28cd2568d3ec2a44e15a08520504de468e7"}, {file = "filelock-3.15.4.tar.gz", hash = "sha256:2207938cbc1844345cb01a5a95524dae30f0ce089eba5b00378295a17e3e90cb"}, @@ -619,7 +655,7 @@ files = [ [package.extras] docs = ["furo (>=2023.9.10)", "sphinx (>=7.2.6)", "sphinx-autodoc-typehints (>=1.25.2)"] testing = ["covdefaults (>=2.3)", "coverage (>=7.3.2)", "diff-cover (>=8.0.1)", "pytest (>=7.4.3)", "pytest-asyncio (>=0.21)", "pytest-cov (>=4.1)", "pytest-mock (>=3.12)", "pytest-timeout (>=2.2)", "virtualenv (>=20.26.2)"] -typing = ["typing-extensions (>=4.8)"] +typing = ["typing-extensions (>=4.8) ; python_version < \"3.11\""] [[package]] name = "future" @@ -627,6 +663,8 @@ version = "1.0.0" description = "Clean single-source support for Python 3 and 2" optional = true python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" +groups = ["main"] +markers = "python_full_version != \"3.12.0\" and extra == \"gkeep\"" files = [ {file = "future-1.0.0-py3-none-any.whl", hash = "sha256:929292d34f5872e70396626ef385ec22355a1fae8ad29e1a734c3e43f9fbc216"}, {file = "future-1.0.0.tar.gz", hash = "sha256:bd2968309307861edae1458a4f8a4f3598c03be43b97521076aebf5d94c07b05"}, @@ -638,6 +676,8 @@ version = "0.13.7" description = "An unofficial Google Keep API client" optional = true python-versions = "*" +groups = ["main"] +markers = "python_version <= \"3.11\" and extra == \"gkeep\"" files = [ {file = "gkeepapi-0.13.7-py2.py3-none-any.whl", hash = "sha256:33fc0f4b1df0f51fcff74a2c71ddc9b65f8c4a7cd75eaf4d4f101ea1dbb3a24d"}, ] @@ -654,6 +694,8 @@ version = "0.16.0" description = "An unofficial Google Keep API client" optional = true python-versions = ">=3.10" +groups = ["main"] +markers = "python_full_version > \"3.12.0\" and extra == \"gkeep\"" files = [ {file = "gkeepapi-0.16.0-py3-none-any.whl", hash = "sha256:0fca50b538d377977aa275b6ee3be6fc6125c9c5efdd33457b25bfe3a09c50e1"}, ] @@ -671,10 +713,12 @@ version = "2.19.1" description = "Google API client core library" optional = false python-versions = ">=3.7" +groups = ["main", "dev"] files = [ {file = "google-api-core-2.19.1.tar.gz", hash = "sha256:f4695f1e3650b316a795108a76a1c416e6afb036199d1c1f1f110916df479ffd"}, {file = "google_api_core-2.19.1-py3-none-any.whl", hash = "sha256:f12a9b8309b5e21d92483bbd47ce2c445861ec7d269ef6784ecc0ea8c1fa6125"}, ] +markers = {main = "extra == \"google\""} [package.dependencies] google-auth = ">=2.14.1,<3.0.dev0" @@ -684,7 +728,7 @@ protobuf = ">=3.19.5,<3.20.0 || >3.20.0,<3.20.1 || >3.20.1,<4.21.0 || >4.21.0,<4 requests = ">=2.18.0,<3.0.0.dev0" [package.extras] -grpc = ["grpcio (>=1.33.2,<2.0dev)", "grpcio (>=1.49.1,<2.0dev)", "grpcio-status (>=1.33.2,<2.0.dev0)", "grpcio-status (>=1.49.1,<2.0.dev0)"] +grpc = ["grpcio (>=1.33.2,<2.0dev)", "grpcio (>=1.49.1,<2.0dev) ; python_version >= \"3.11\"", "grpcio-status (>=1.33.2,<2.0.dev0)", "grpcio-status (>=1.49.1,<2.0.dev0) ; python_version >= \"3.11\""] grpcgcp = ["grpcio-gcp (>=0.2.2,<1.0.dev0)"] grpcio-gcp = ["grpcio-gcp (>=0.2.2,<1.0.dev0)"] @@ -694,10 +738,12 @@ version = "2.141.0" description = "Google API Client Library for Python" optional = false python-versions = ">=3.7" +groups = ["main", "dev"] files = [ {file = "google_api_python_client-2.141.0-py2.py3-none-any.whl", hash = "sha256:43c05322b91791204465291b3852718fae38d4f84b411d8be847c4f86882652a"}, {file = "google_api_python_client-2.141.0.tar.gz", hash = "sha256:0f225b1f45d5a6f8c2a400f48729f5d6da9a81138e81e0478d61fdd8edf6563a"}, ] +markers = {main = "extra == \"google\""} [package.dependencies] google-api-core = ">=1.31.5,<2.0.dev0 || >2.3.0,<3.0.0.dev0" @@ -712,6 +758,7 @@ version = "1.27.0" description = "Type stubs for google-api-python-client" optional = false python-versions = "<4.0,>=3.7" +groups = ["dev"] files = [ {file = "google_api_python_client_stubs-1.27.0-py3-none-any.whl", hash = "sha256:3c1f9f2a7cac8d1e9a7e84ed24e6c29cf4c643b0f94e39ed09ac1b7e91ab239a"}, {file = "google_api_python_client_stubs-1.27.0.tar.gz", hash = "sha256:148e16613e070969727f39691e23a73cdb87c65a4fc8133abd4c41d17b80b313"}, @@ -728,10 +775,12 @@ version = "2.33.0" description = "Google Authentication Library" optional = false python-versions = ">=3.7" +groups = ["main", "dev"] files = [ {file = "google_auth-2.33.0-py2.py3-none-any.whl", hash = "sha256:8eff47d0d4a34ab6265c50a106a3362de6a9975bb08998700e389f857e4d39df"}, {file = "google_auth-2.33.0.tar.gz", hash = "sha256:d6a52342160d7290e334b4d47ba390767e4438ad0d45b7630774533e82655b95"}, ] +markers = {main = "extra == \"google\""} [package.dependencies] cachetools = ">=2.0.0,<6.0" @@ -751,10 +800,12 @@ version = "0.2.0" description = "Google Authentication Library: httplib2 transport" optional = false python-versions = "*" +groups = ["main", "dev"] files = [ {file = "google-auth-httplib2-0.2.0.tar.gz", hash = "sha256:38aa7badf48f974f1eb9861794e9c0cb2a0511a4ec0679b1f886d108f5640e05"}, {file = "google_auth_httplib2-0.2.0-py2.py3-none-any.whl", hash = "sha256:b65a0a2123300dd71281a7bf6e64d65a0759287df52729bdd1ae2e47dc311a3d"}, ] +markers = {main = "extra == \"google\""} [package.dependencies] google-auth = "*" @@ -766,6 +817,8 @@ version = "0.4.6" description = "Google Authentication Library" optional = true python-versions = ">=3.6" +groups = ["main"] +markers = "extra == \"google\"" files = [ {file = "google-auth-oauthlib-0.4.6.tar.gz", hash = "sha256:a90a072f6993f2c327067bf65270046384cda5a8ecb20b94ea9a687f1f233a7a"}, {file = "google_auth_oauthlib-0.4.6-py2.py3-none-any.whl", hash = "sha256:3f2a6e802eebbb6fb736a370fbf3b055edcb6b52878bf2f26330b5e041316c73"}, @@ -784,10 +837,12 @@ version = "1.63.2" description = "Common protobufs used in Google APIs" optional = false python-versions = ">=3.7" +groups = ["main", "dev"] files = [ {file = "googleapis-common-protos-1.63.2.tar.gz", hash = "sha256:27c5abdffc4911f28101e635de1533fb4cfd2c37fbaa9174587c799fac90aa87"}, {file = "googleapis_common_protos-1.63.2-py2.py3-none-any.whl", hash = "sha256:27a2499c7e8aff199665b22741997e485eccc8645aa9176c7c988e6fae507945"}, ] +markers = {main = "extra == \"google\""} [package.dependencies] protobuf = ">=3.20.2,<4.21.1 || >4.21.1,<4.21.2 || >4.21.2,<4.21.3 || >4.21.3,<4.21.4 || >4.21.4,<4.21.5 || >4.21.5,<6.0.0.dev0" @@ -801,6 +856,8 @@ version = "1.1.1" description = "A python client library for Google Play Services OAuth." optional = true python-versions = "<4.0,>=3.8" +groups = ["main"] +markers = "python_full_version != \"3.12.0\" and extra == \"gkeep\"" files = [ {file = "gpsoauth-1.1.1-py3-none-any.whl", hash = "sha256:0fa7959b1d52fc625d93928e4ad4349ac79c6bfe811981d4f91f3b687e1b6fc1"}, {file = "gpsoauth-1.1.1.tar.gz", hash = "sha256:58202ed303397d2927b464dc95e2714bffff85a1b0f88bf68f3ad63859ebe435"}, @@ -817,6 +874,8 @@ version = "0.14.0" description = "A pure-Python, bring-your-own-I/O implementation of HTTP/1.1" optional = true python-versions = ">=3.7" +groups = ["main"] +markers = "extra == \"notion\"" files = [ {file = "h11-0.14.0-py3-none-any.whl", hash = "sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761"}, {file = "h11-0.14.0.tar.gz", hash = "sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d"}, @@ -828,6 +887,8 @@ version = "1.0.5" description = "A minimal low-level HTTP client." optional = true python-versions = ">=3.8" +groups = ["main"] +markers = "extra == \"notion\"" files = [ {file = "httpcore-1.0.5-py3-none-any.whl", hash = "sha256:421f18bac248b25d310f3cacd198d55b8e6125c107797b609ff9b7a6ba7991b5"}, {file = "httpcore-1.0.5.tar.gz", hash = "sha256:34a38e2f9291467ee3b44e89dd52615370e152954ba21721378a87b2960f7a61"}, @@ -849,10 +910,12 @@ version = "0.22.0" description = "A comprehensive HTTP client library." optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +groups = ["main", "dev"] files = [ {file = "httplib2-0.22.0-py3-none-any.whl", hash = "sha256:14ae0a53c1ba8f3d37e9e27cf37eabb0fb9980f435ba405d546948b009dd64dc"}, {file = "httplib2-0.22.0.tar.gz", hash = "sha256:d7a10bc5ef5ab08322488bde8c726eeee5c8618723fdb399597ec58f3d82df81"}, ] +markers = {main = "extra == \"google\""} [package.dependencies] pyparsing = {version = ">=2.4.2,<3.0.0 || >3.0.0,<3.0.1 || >3.0.1,<3.0.2 || >3.0.2,<3.0.3 || >3.0.3,<4", markers = "python_version > \"3.0\""} @@ -863,6 +926,8 @@ version = "0.27.0" description = "The next generation HTTP client." optional = true python-versions = ">=3.8" +groups = ["main"] +markers = "extra == \"notion\"" files = [ {file = "httpx-0.27.0-py3-none-any.whl", hash = "sha256:71d5465162c13681bff01ad59b2cc68dd838ea1f10e51574bac27103f00c91a5"}, {file = "httpx-0.27.0.tar.gz", hash = "sha256:a0cb88a46f32dc874e04ee956e4c2764aba2aa228f650b06788ba6bda2962ab5"}, @@ -876,7 +941,7 @@ idna = "*" sniffio = "*" [package.extras] -brotli = ["brotli", "brotlicffi"] +brotli = ["brotli ; platform_python_implementation == \"CPython\"", "brotlicffi ; platform_python_implementation != \"CPython\""] cli = ["click (==8.*)", "pygments (==2.*)", "rich (>=10,<14)"] http2 = ["h2 (>=3,<5)"] socks = ["socksio (==1.*)"] @@ -887,6 +952,8 @@ version = "5.0.13" description = "iCalendar parser/generator" optional = true python-versions = ">=3.7" +groups = ["main"] +markers = "extra == \"caldav\"" files = [ {file = "icalendar-5.0.13-py3-none-any.whl", hash = "sha256:5ded5415e2e1edef5ab230024a75878a7a81d518a3b1ae4f34bf20b173c84dc2"}, {file = "icalendar-5.0.13.tar.gz", hash = "sha256:92799fde8cce0b61daa8383593836d1e19136e504fa1671f471f98be9b029706"}, @@ -903,6 +970,7 @@ version = "2.6.0" description = "File identification library for Python" optional = false python-versions = ">=3.8" +groups = ["dev"] files = [ {file = "identify-2.6.0-py2.py3-none-any.whl", hash = "sha256:e79ae4406387a9d300332b5fd366d8994f1525e8414984e1a59e058b2eda2dd0"}, {file = "identify-2.6.0.tar.gz", hash = "sha256:cb171c685bdc31bcc4c1734698736a7d5b6c8bf2e0c15117f4d469c8640ae5cf"}, @@ -917,10 +985,12 @@ version = "2.10" description = "Internationalized Domain Names in Applications (IDNA)" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +groups = ["main", "dev"] files = [ {file = "idna-2.10-py2.py3-none-any.whl", hash = "sha256:b97d804b1e9b523befed77c48dacec60e6dcb0b5391d57af6a65a312a90648c0"}, {file = "idna-2.10.tar.gz", hash = "sha256:b307872f855b18632ce0c21c5e45be78c0ea7ae4c15c828c20788b26921eb3f6"}, ] +markers = {main = "python_version <= \"3.11\" and (extra == \"gkeep\" or extra == \"google\" or extra == \"asana\" or extra == \"caldav\" or extra == \"notion\")", dev = "python_version <= \"3.11\""} [[package]] name = "idna" @@ -928,10 +998,12 @@ version = "3.7" description = "Internationalized Domain Names in Applications (IDNA)" optional = false python-versions = ">=3.5" +groups = ["main", "dev"] files = [ {file = "idna-3.7-py3-none-any.whl", hash = "sha256:82fee1fc78add43492d3a1898bfa6d8a904cc97d8427f683ed8e798d07761aa0"}, {file = "idna-3.7.tar.gz", hash = "sha256:028ff3aadf0609c1fd278d8ea3089299412a7a8b9bd005dd08b9f8285bcb5cfc"}, ] +markers = {main = "python_full_version >= \"3.12.0\" and (python_full_version > \"3.12.0\" or extra == \"google\" or extra == \"asana\" or extra == \"caldav\" or extra == \"notion\") and (extra == \"gkeep\" or extra == \"google\" or extra == \"asana\" or extra == \"caldav\" or extra == \"notion\")", dev = "python_full_version >= \"3.12.0\""} [[package]] name = "importlib-resources" @@ -939,6 +1011,8 @@ version = "6.4.2" description = "Read resources from Python packages" optional = false python-versions = ">=3.8" +groups = ["dev"] +markers = "python_version < \"3.9\"" files = [ {file = "importlib_resources-6.4.2-py3-none-any.whl", hash = "sha256:8bba8c54a8a3afaa1419910845fa26ebd706dc716dd208d9b158b4b6966f5c5c"}, {file = "importlib_resources-6.4.2.tar.gz", hash = "sha256:6cbfbefc449cc6e2095dd184691b7a12a04f40bc75dd4c55d31c34f174cdf57a"}, @@ -949,7 +1023,7 @@ zipp = {version = ">=3.1.0", markers = "python_version < \"3.10\""} [package.extras] doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] -test = ["jaraco.test (>=5.4)", "pytest (>=6,!=8.1.*)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy", "pytest-ruff (>=0.2.1)", "zipp (>=3.17)"] +test = ["jaraco.test (>=5.4)", "pytest (>=6,!=8.1.*)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy", "pytest-ruff (>=0.2.1) ; sys_platform != \"cygwin\"", "zipp (>=3.17)"] [[package]] name = "iniconfig" @@ -957,6 +1031,7 @@ version = "2.0.0" description = "brain-dead simple config-ini parsing" optional = false python-versions = ">=3.7" +groups = ["dev"] files = [ {file = "iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374"}, {file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"}, @@ -968,6 +1043,7 @@ version = "5.13.2" description = "A Python utility / library to sort Python imports." optional = false python-versions = ">=3.8.0" +groups = ["dev"] files = [ {file = "isort-5.13.2-py3-none-any.whl", hash = "sha256:8ca5e72a8d85860d5a3fa69b8745237f2939afe12dbf656afbcb47fe72d947a6"}, {file = "isort-5.13.2.tar.gz", hash = "sha256:48fdfcb9face5d58a4f6dde2e72a1fb8dcaf8ab26f95ab49fab84c2ddefb0109"}, @@ -982,6 +1058,7 @@ version = "1.1.5" description = "Synchronize items bi-directionally between two different sources" optional = false python-versions = ">=3.8,<4.0" +groups = ["main"] files = [ {file = "item_synchronizer-1.1.5-py3-none-any.whl", hash = "sha256:b57d86689fc49fd163a32464e6505b1d122a00f8a26ca5cb5d80bfde2da1fef0"}, {file = "item_synchronizer-1.1.5.tar.gz", hash = "sha256:94aa402c7e844fd4e9da34ca9c9c2f5efd55765e48945282a60f266031b5203e"}, @@ -997,6 +1074,7 @@ version = "4.23.0" description = "An implementation of JSON Schema validation for Python" optional = false python-versions = ">=3.8" +groups = ["dev"] files = [ {file = "jsonschema-4.23.0-py3-none-any.whl", hash = "sha256:fbadb6f8b144a8f8cf9f0b89ba94501d143e50411a1278633f56a7acf7fd5566"}, {file = "jsonschema-4.23.0.tar.gz", hash = "sha256:d71497fef26351a33265337fa77ffeb82423f3ea21283cd9467bb03999266bc4"}, @@ -1020,6 +1098,7 @@ version = "2023.12.1" description = "The JSON Schema meta-schemas and vocabularies, exposed as a Registry" optional = false python-versions = ">=3.8" +groups = ["dev"] files = [ {file = "jsonschema_specifications-2023.12.1-py3-none-any.whl", hash = "sha256:87e4fdf3a94858b8a2ba2778d9ba57d8a9cafca7c7489c46ba0d30a8bc6a9c3c"}, {file = "jsonschema_specifications-2023.12.1.tar.gz", hash = "sha256:48a76787b3e70f5ed53f1160d2b81f586e4ca6d1548c5de7085d1682674764cc"}, @@ -1035,6 +1114,8 @@ version = "1.2.6" description = "Kitchen contains a cornucopia of useful code" optional = true python-versions = "*" +groups = ["main"] +markers = "extra == \"tw\"" files = [ {file = "kitchen-1.2.6.tar.gz", hash = "sha256:b84cf582f1bd1556b60ebc7370b9d331eb9247b6b070ce89dfe959cba2c0b03c"}, ] @@ -1045,6 +1126,7 @@ version = "1.10.0" description = "A fast and thorough lazy object proxy." optional = false python-versions = ">=3.8" +groups = ["dev"] files = [ {file = "lazy-object-proxy-1.10.0.tar.gz", hash = "sha256:78247b6d45f43a52ef35c25b5581459e85117225408a4128a3daf8bf9648ac69"}, {file = "lazy_object_proxy-1.10.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:855e068b0358ab916454464a884779c7ffa312b8925c6f7401e952dcf3b89977"}, @@ -1091,6 +1173,7 @@ version = "0.5.3" description = "Python logging made (stupidly) simple" optional = false python-versions = ">=3.5" +groups = ["main"] files = [ {file = "loguru-0.5.3-py3-none-any.whl", hash = "sha256:f8087ac396b5ee5f67c963b495d615ebbceac2796379599820e324419d53667c"}, {file = "loguru-0.5.3.tar.gz", hash = "sha256:b28e72ac7a98be3d28ad28570299a393dfcd32e5e3f6a353dec94675767b6319"}, @@ -1101,7 +1184,7 @@ colorama = {version = ">=0.3.4", markers = "sys_platform == \"win32\""} win32-setctime = {version = ">=1.0.0", markers = "sys_platform == \"win32\""} [package.extras] -dev = ["Sphinx (>=2.2.1)", "black (>=19.10b0)", "codecov (>=2.0.15)", "colorama (>=0.3.4)", "flake8 (>=3.7.7)", "isort (>=5.1.1)", "pytest (>=4.6.2)", "pytest-cov (>=2.7.1)", "sphinx-autobuild (>=0.7.1)", "sphinx-rtd-theme (>=0.4.3)", "tox (>=3.9.0)", "tox-travis (>=0.12)"] +dev = ["Sphinx (>=2.2.1)", "black (>=19.10b0) ; python_version >= \"3.6\"", "codecov (>=2.0.15)", "colorama (>=0.3.4)", "flake8 (>=3.7.7)", "isort (>=5.1.1) ; python_version >= \"3.6\"", "pytest (>=4.6.2)", "pytest-cov (>=2.7.1)", "sphinx-autobuild (>=0.7.1)", "sphinx-rtd-theme (>=0.4.3)", "tox (>=3.9.0)", "tox-travis (>=0.12)"] [[package]] name = "lxml" @@ -1109,6 +1192,8 @@ version = "5.3.0" description = "Powerful and Pythonic XML processing library combining libxml2/libxslt with the ElementTree API." optional = true python-versions = ">=3.6" +groups = ["main"] +markers = "extra == \"caldav\"" files = [ {file = "lxml-5.3.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:dd36439be765e2dde7660212b5275641edbc813e7b24668831a5c8ac91180656"}, {file = "lxml-5.3.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ae5fe5c4b525aa82b8076c1a59d642c17b6e8739ecf852522c6321852178119d"}, @@ -1263,6 +1348,7 @@ version = "0.7.0" description = "McCabe checker, plugin for flake8" optional = false python-versions = ">=3.6" +groups = ["dev"] files = [ {file = "mccabe-0.7.0-py2.py3-none-any.whl", hash = "sha256:6c2d30ab6be0e4a46919781807b4f0d834ebdd6c6e3dca0bda5a15f863427b6e"}, {file = "mccabe-0.7.0.tar.gz", hash = "sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325"}, @@ -1274,6 +1360,7 @@ version = "5.1.0" description = "Rolling backport of unittest.mock for all Pythons" optional = false python-versions = ">=3.6" +groups = ["dev"] files = [ {file = "mock-5.1.0-py3-none-any.whl", hash = "sha256:18c694e5ae8a208cdb3d2c20a993ca1a7b0efa258c247a1e565150f477f83744"}, {file = "mock-5.1.0.tar.gz", hash = "sha256:5e96aad5ccda4718e0a229ed94b2024df75cc2d55575ba5762d31f5767b8767d"}, @@ -1290,6 +1377,7 @@ version = "1.11.1" description = "Optional static typing for Python" optional = false python-versions = ">=3.8" +groups = ["dev"] files = [ {file = "mypy-1.11.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:a32fc80b63de4b5b3e65f4be82b4cfa362a46702672aa6a0f443b4689af7008c"}, {file = "mypy-1.11.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c1952f5ea8a5a959b05ed5f16452fddadbaae48b5d39235ab4c3fc444d5fd411"}, @@ -1337,6 +1425,7 @@ version = "1.0.0" description = "Type system extensions for programs checked with the mypy type checker." optional = false python-versions = ">=3.5" +groups = ["dev"] files = [ {file = "mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d"}, {file = "mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"}, @@ -1348,6 +1437,7 @@ version = "1.9.1" description = "Node.js virtual environment builder" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" +groups = ["dev"] files = [ {file = "nodeenv-1.9.1-py2.py3-none-any.whl", hash = "sha256:ba11c9782d29c27c70ffbdda2d7415098754709be8a7056d79a737cd901155c9"}, {file = "nodeenv-1.9.1.tar.gz", hash = "sha256:6ec12890a2dab7946721edbfbcd91f3319c6ccc9aec47be7c7e6b7011ee6645f"}, @@ -1359,6 +1449,8 @@ version = "0.7.1" description = "Python client for the official Notion API" optional = true python-versions = ">=3.7, <4" +groups = ["main"] +markers = "extra == \"notion\"" files = [ {file = "notion-client-0.7.1.tar.gz", hash = "sha256:58519c4340f99c2b7651a1d671f07411052fb46786fcb41df71c60e6b1b144ac"}, {file = "notion_client-0.7.1-py2.py3-none-any.whl", hash = "sha256:ff9c16beb4c74f59abbd8c8764e078c095791d0b80288eb9e54ca507316c53e1"}, @@ -1373,6 +1465,8 @@ version = "3.2.2" description = "A generic, spec-compliant, thorough implementation of the OAuth request-signing logic" optional = true python-versions = ">=3.6" +groups = ["main"] +markers = "extra == \"google\" or extra == \"asana\"" files = [ {file = "oauthlib-3.2.2-py3-none-any.whl", hash = "sha256:8139f29aac13e25d502680e9e19963e83f16838d48a0d71c287fe40e7067fbca"}, {file = "oauthlib-3.2.2.tar.gz", hash = "sha256:9859c40929662bec5d64f34d01c99e093149682a3f38915dc0655d5a633dd918"}, @@ -1389,10 +1483,12 @@ version = "23.2" description = "Core utilities for Python packages" optional = false python-versions = ">=3.7" +groups = ["main", "dev"] files = [ {file = "packaging-23.2-py3-none-any.whl", hash = "sha256:8c491190033a9af7e1d931d0b5dacc2ef47509b34dd0de67ed209b5203fc88c7"}, {file = "packaging-23.2.tar.gz", hash = "sha256:048fb0e9405036518eaaf48a55953c750c11e1a1b68e0dd1a9d62ed0c092cfc5"}, ] +markers = {main = "extra == \"tw\""} [[package]] name = "pathspec" @@ -1400,6 +1496,7 @@ version = "0.12.1" description = "Utility library for gitignore style pattern matching of file paths." optional = false python-versions = ">=3.8" +groups = ["dev"] files = [ {file = "pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08"}, {file = "pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712"}, @@ -1411,6 +1508,8 @@ version = "1.3.10" description = "Resolve a name to an object." optional = false python-versions = ">=3.6" +groups = ["dev"] +markers = "python_version < \"3.9\"" files = [ {file = "pkgutil_resolve_name-1.3.10-py3-none-any.whl", hash = "sha256:ca27cc078d25c5ad71a9de0a7a330146c4e014c2462d9af19c6b828280649c5e"}, {file = "pkgutil_resolve_name-1.3.10.tar.gz", hash = "sha256:357d6c9e6a755653cfd78893817c0853af365dd51ec97f3d358a819373bbd174"}, @@ -1422,6 +1521,7 @@ version = "4.2.2" description = "A small Python package for determining appropriate platform-specific dirs, e.g. a `user data dir`." optional = false python-versions = ">=3.8" +groups = ["dev"] files = [ {file = "platformdirs-4.2.2-py3-none-any.whl", hash = "sha256:2d7a1657e36a80ea911db832a8a6ece5ee53d8de21edd5cc5879af6530b1bfee"}, {file = "platformdirs-4.2.2.tar.gz", hash = "sha256:38b7b51f512eed9e84a22788b4bce1de17c0adb134d6becb09836e37d8654cd3"}, @@ -1438,6 +1538,7 @@ version = "1.5.0" description = "plugin and hook calling mechanisms for python" optional = false python-versions = ">=3.8" +groups = ["dev"] files = [ {file = "pluggy-1.5.0-py3-none-any.whl", hash = "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669"}, {file = "pluggy-1.5.0.tar.gz", hash = "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1"}, @@ -1453,6 +1554,7 @@ version = "2.21.0" description = "A framework for managing and maintaining multi-language pre-commit hooks." optional = false python-versions = ">=3.7" +groups = ["dev"] files = [ {file = "pre_commit-2.21.0-py2.py3-none-any.whl", hash = "sha256:e2f91727039fc39a92f58a588a25b87f936de6567eed4f0e673e0507edc75bad"}, {file = "pre_commit-2.21.0.tar.gz", hash = "sha256:31ef31af7e474a8d8995027fefdfcf509b5c913ff31f2015b4ec4beb26a6f658"}, @@ -1471,10 +1573,12 @@ version = "1.24.0" description = "Beautiful, Pythonic protocol buffers." optional = false python-versions = ">=3.7" +groups = ["main", "dev"] files = [ {file = "proto-plus-1.24.0.tar.gz", hash = "sha256:30b72a5ecafe4406b0d339db35b56c4059064e69227b8c3bda7462397f966445"}, {file = "proto_plus-1.24.0-py3-none-any.whl", hash = "sha256:402576830425e5f6ce4c2a6702400ac79897dab0b4343821aa5188b0fab81a12"}, ] +markers = {main = "extra == \"google\""} [package.dependencies] protobuf = ">=3.19.0,<6.0.0dev" @@ -1488,6 +1592,7 @@ version = "5.27.3" description = "" optional = false python-versions = ">=3.8" +groups = ["main", "dev"] files = [ {file = "protobuf-5.27.3-cp310-abi3-win32.whl", hash = "sha256:dcb307cd4ef8fec0cf52cb9105a03d06fbb5275ce6d84a6ae33bc6cf84e0a07b"}, {file = "protobuf-5.27.3-cp310-abi3-win_amd64.whl", hash = "sha256:16ddf3f8c6c41e1e803da7abea17b1793a97ef079a912e42351eabb19b2cffe7"}, @@ -1501,6 +1606,7 @@ files = [ {file = "protobuf-5.27.3-py3-none-any.whl", hash = "sha256:8572c6533e544ebf6899c360e91d6bcbbee2549251643d32c52cf8a5de295ba5"}, {file = "protobuf-5.27.3.tar.gz", hash = "sha256:82460903e640f2b7e34ee81a947fdaad89de796d324bcbc38ff5430bcdead82c"}, ] +markers = {main = "extra == \"google\""} [[package]] name = "pyasn1" @@ -1508,10 +1614,12 @@ version = "0.6.0" description = "Pure-Python implementation of ASN.1 types and DER/BER/CER codecs (X.208)" optional = false python-versions = ">=3.8" +groups = ["main", "dev"] files = [ {file = "pyasn1-0.6.0-py2.py3-none-any.whl", hash = "sha256:cca4bb0f2df5504f02f6f8a775b6e416ff9b0b3b16f7ee80b5a3153d9b804473"}, {file = "pyasn1-0.6.0.tar.gz", hash = "sha256:3a35ab2c4b5ef98e17dfdec8ab074046fbda76e281c5a706ccd82328cfc8f64c"}, ] +markers = {main = "extra == \"google\""} [[package]] name = "pyasn1-modules" @@ -1519,10 +1627,12 @@ version = "0.4.0" description = "A collection of ASN.1-based protocols modules" optional = false python-versions = ">=3.8" +groups = ["main", "dev"] files = [ {file = "pyasn1_modules-0.4.0-py3-none-any.whl", hash = "sha256:be04f15b66c206eed667e0bb5ab27e2b1855ea54a842e5037738099e8ca4ae0b"}, {file = "pyasn1_modules-0.4.0.tar.gz", hash = "sha256:831dbcea1b177b28c9baddf4c6d1013c24c3accd14a1873fffaa6a2e905f17b6"}, ] +markers = {main = "extra == \"google\""} [package.dependencies] pyasn1 = ">=0.4.6,<0.7.0" @@ -1533,6 +1643,8 @@ version = "2.22" description = "C parser in Python" optional = true python-versions = ">=3.8" +groups = ["main"] +markers = "extra == \"fs\"" files = [ {file = "pycparser-2.22-py3-none-any.whl", hash = "sha256:c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc"}, {file = "pycparser-2.22.tar.gz", hash = "sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6"}, @@ -1544,6 +1656,8 @@ version = "3.20.0" description = "Cryptographic library for Python" optional = true python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +groups = ["main"] +markers = "python_full_version != \"3.12.0\" and extra == \"gkeep\"" files = [ {file = "pycryptodomex-3.20.0-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:645bd4ca6f543685d643dadf6a856cc382b654cc923460e3a10a49c1b3832aeb"}, {file = "pycryptodomex-3.20.0-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:ff5c9a67f8a4fba4aed887216e32cbc48f2a6fb2673bb10a99e43be463e15913"}, @@ -1585,6 +1699,8 @@ version = "4.7.0" description = "pyfakefs implements a fake file system that mocks the Python file system modules." optional = false python-versions = ">=3.7" +groups = ["dev"] +markers = "python_version <= \"3.11\"" files = [ {file = "pyfakefs-4.7.0-py3-none-any.whl", hash = "sha256:29203a7482b25406dd3ea41c8740be2697c6058b0f6577485c3ae9cd4c5e96cd"}, {file = "pyfakefs-4.7.0.tar.gz", hash = "sha256:f22d30d93d2989bf2d2c67b606a14cbab2df0be912c09dcdb590ea4931073ade"}, @@ -1596,6 +1712,8 @@ version = "5.6.0" description = "pyfakefs implements a fake file system that mocks the Python file system modules." optional = false python-versions = ">=3.7" +groups = ["dev"] +markers = "python_full_version > \"3.12.0\"" files = [ {file = "pyfakefs-5.6.0-py3-none-any.whl", hash = "sha256:1a45bba8615323ec29d65929d32dc66d7b59a1e60a02109950440edb0486c539"}, {file = "pyfakefs-5.6.0.tar.gz", hash = "sha256:7a549b32865aa97d8ba6538285a93816941d9b7359be2954ac60ec36b277e879"}, @@ -1607,6 +1725,7 @@ version = "2.17.7" description = "python code static checker" optional = false python-versions = ">=3.7.2" +groups = ["dev"] files = [ {file = "pylint-2.17.7-py3-none-any.whl", hash = "sha256:27a8d4c7ddc8c2f8c18aa0050148f89ffc09838142193fdbe98f172781a3ff87"}, {file = "pylint-2.17.7.tar.gz", hash = "sha256:f4fcac7ae74cfe36bc8451e931d8438e4a476c20314b1101c458ad0f05191fad"}, @@ -1636,10 +1755,12 @@ version = "3.1.2" description = "pyparsing module - Classes and methods to define and execute parsing grammars" optional = false python-versions = ">=3.6.8" +groups = ["main", "dev"] files = [ {file = "pyparsing-3.1.2-py3-none-any.whl", hash = "sha256:f9db75911801ed778fe61bb643079ff86601aca99fcae6345aa67292038fb742"}, {file = "pyparsing-3.1.2.tar.gz", hash = "sha256:a1bac0ce561155ecc3ed78ca94d3c9378656ad4c94c1270de543f621420f94ad"}, ] +markers = {main = "extra == \"google\""} [package.extras] diagrams = ["jinja2", "railroad-diagrams"] @@ -1650,6 +1771,7 @@ version = "1.1.376" description = "Command line wrapper for pyright" optional = false python-versions = ">=3.7" +groups = ["dev"] files = [ {file = "pyright-1.1.376-py3-none-any.whl", hash = "sha256:0f2473b12c15c46b3207f0eec224c3cea2bdc07cd45dd4a037687cbbca0fbeff"}, {file = "pyright-1.1.376.tar.gz", hash = "sha256:bffd63b197cd0810395bb3245c06b01f95a85ddf6bfa0e5644ed69c841e954dd"}, @@ -1668,6 +1790,7 @@ version = "8.3.2" description = "pytest: simple powerful testing with Python" optional = false python-versions = ">=3.8" +groups = ["dev"] files = [ {file = "pytest-8.3.2-py3-none-any.whl", hash = "sha256:4ba08f9ae7dcf84ded419494d229b48d0903ea6407b030eaec46df5e6a73bba5"}, {file = "pytest-8.3.2.tar.gz", hash = "sha256:c132345d12ce551242c87269de812483f5bcc87cdbb4722e48487ba194f9fdce"}, @@ -1690,6 +1813,7 @@ version = "2.9.0.post0" description = "Extensions to the standard Python datetime module" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" +groups = ["main"] files = [ {file = "python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3"}, {file = "python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427"}, @@ -1704,6 +1828,8 @@ version = "2023.4" description = "World timezone definitions, modern and historical" optional = true python-versions = "*" +groups = ["main"] +markers = "extra == \"caldav\" or extra == \"tw\"" files = [ {file = "pytz-2023.4-py2.py3-none-any.whl", hash = "sha256:f90ef520d95e7c46951105338d918664ebfd6f1d995bd7d153127ce90efafa6a"}, {file = "pytz-2023.4.tar.gz", hash = "sha256:31d4583c4ed539cd037956140d695e42c033a19e984bfce9964a3f7d59bc2b40"}, @@ -1715,6 +1841,7 @@ version = "3.16.0" description = "A tool to automatically upgrade syntax for newer versions." optional = false python-versions = ">=3.8.1" +groups = ["dev"] files = [ {file = "pyupgrade-3.16.0-py2.py3-none-any.whl", hash = "sha256:7a54ee28f3024d027048d49d101e5c702e88c85edc3a1d08b636c50ebef2a97d"}, {file = "pyupgrade-3.16.0.tar.gz", hash = "sha256:237893a05d5b117259b31b423f23cbae4bce0b7eae57ba9a52c06098c2ddd76f"}, @@ -1729,6 +1856,7 @@ version = "5.3.1" description = "YAML parser and emitter for Python" optional = false python-versions = "*" +groups = ["main", "dev"] files = [ {file = "PyYAML-5.3.1-cp27-cp27m-win32.whl", hash = "sha256:74809a57b329d6cc0fdccee6318f44b9b8649961fa73144a98735b0aaf029f1f"}, {file = "PyYAML-5.3.1-cp27-cp27m-win_amd64.whl", hash = "sha256:240097ff019d7c70a4922b6869d8a86407758333f02203e0fc6ff79c5dcede76"}, @@ -1751,6 +1879,8 @@ version = "2.2.3" description = "A Python module which repeats ICalendar events by RRULE, RDATE and EXDATE." optional = true python-versions = "*" +groups = ["main"] +markers = "extra == \"caldav\"" files = [ {file = "recurring_ical_events-2.2.3-py3-none-any.whl", hash = "sha256:c1451960449ff656f07f32620c4f56fe352a5fef486e46d077eea9c608c300fb"}, {file = "recurring_ical_events-2.2.3.tar.gz", hash = "sha256:05548cf864447b099b6b7df240396e8f54e0ff47c93b77f719b799beadf1b98e"}, @@ -1769,6 +1899,7 @@ version = "0.35.1" description = "JSON Referencing + Python" optional = false python-versions = ">=3.8" +groups = ["dev"] files = [ {file = "referencing-0.35.1-py3-none-any.whl", hash = "sha256:eda6d3234d62814d1c64e305c1331c9a3a6132da475ab6382eaa997b21ee75de"}, {file = "referencing-0.35.1.tar.gz", hash = "sha256:25b42124a6c8b632a425174f24087783efb348a6f1e0008e63cd4466fedf703c"}, @@ -1784,10 +1915,12 @@ version = "2.23.0" description = "Python HTTP for Humans." optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +groups = ["main", "dev"] files = [ {file = "requests-2.23.0-py2.py3-none-any.whl", hash = "sha256:43999036bfa82904b6af1d99e4882b560e5e2c68e5c4b0aa03b655f3d7d73fee"}, {file = "requests-2.23.0.tar.gz", hash = "sha256:b3f43d496c6daba4493e7c431722aeb7dbc6288f52a6e04e7b6023b0247817e6"}, ] +markers = {main = "python_version <= \"3.11\" and (extra == \"gkeep\" or extra == \"google\" or extra == \"asana\" or extra == \"caldav\")", dev = "python_version <= \"3.11\""} [package.dependencies] certifi = ">=2017.4.17" @@ -1797,7 +1930,7 @@ urllib3 = ">=1.21.1,<1.25.0 || >1.25.0,<1.25.1 || >1.25.1,<1.26" [package.extras] security = ["cryptography (>=1.3.4)", "pyOpenSSL (>=0.14)"] -socks = ["PySocks (>=1.5.6,!=1.5.7)", "win-inet-pton"] +socks = ["PySocks (>=1.5.6,!=1.5.7)", "win-inet-pton ; sys_platform == \"win32\" and python_version == \"2.7\""] [[package]] name = "requests" @@ -1805,10 +1938,12 @@ version = "2.32.3" description = "Python HTTP for Humans." optional = false python-versions = ">=3.8" +groups = ["main", "dev"] files = [ {file = "requests-2.32.3-py3-none-any.whl", hash = "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6"}, {file = "requests-2.32.3.tar.gz", hash = "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760"}, ] +markers = {main = "python_full_version >= \"3.12.0\" and (python_full_version > \"3.12.0\" or extra == \"google\" or extra == \"asana\" or extra == \"caldav\") and (extra == \"gkeep\" or extra == \"google\" or extra == \"asana\" or extra == \"caldav\")", dev = "python_full_version >= \"3.12.0\""} [package.dependencies] certifi = ">=2017.4.17" @@ -1826,6 +1961,8 @@ version = "1.3.1" description = "OAuthlib authentication support for Requests." optional = true python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +groups = ["main"] +markers = "extra == \"google\" or extra == \"asana\"" files = [ {file = "requests-oauthlib-1.3.1.tar.gz", hash = "sha256:75beac4a47881eeb94d5ea5d6ad31ef88856affe2332b9aafb52c6452ccf0d7a"}, {file = "requests_oauthlib-1.3.1-py2.py3-none-any.whl", hash = "sha256:2577c501a2fb8d05a304c09d090d6e47c306fef15809d102b327cf8364bddab5"}, @@ -1844,6 +1981,7 @@ version = "6.2" description = "Format dates according to the RFC 3339." optional = false python-versions = "*" +groups = ["main"] files = [ {file = "rfc3339-6.2-py3-none-any.whl", hash = "sha256:f44316b21b21db90a625cde04ebb0d46268f153e6093021fa5893e92a96f58a3"}, {file = "rfc3339-6.2.tar.gz", hash = "sha256:d53c3b5eefaef892b7240ba2a91fef012e86faa4d0a0ca782359c490e00ad4d0"}, @@ -1855,6 +1993,7 @@ version = "0.20.0" description = "Python bindings to Rust's persistent data structures (rpds)" optional = false python-versions = ">=3.8" +groups = ["dev"] files = [ {file = "rpds_py-0.20.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:3ad0fda1635f8439cde85c700f964b23ed5fc2d28016b32b9ee5fe30da5c84e2"}, {file = "rpds_py-0.20.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9bb4a0d90fdb03437c109a17eade42dfbf6190408f29b2744114d11586611d6f"}, @@ -1967,10 +2106,12 @@ version = "4.9" description = "Pure-Python RSA implementation" optional = false python-versions = ">=3.6,<4" +groups = ["main", "dev"] files = [ {file = "rsa-4.9-py3-none-any.whl", hash = "sha256:90260d9058e514786967344d0ef75fa8727eed8a7d2e43ce9f4bcf1b536174f7"}, {file = "rsa-4.9.tar.gz", hash = "sha256:e38464a49c6c85d7f1351b0126661487a7e0a14a50f1675ec50eb34d4f20ef21"}, ] +markers = {main = "extra == \"google\""} [package.dependencies] pyasn1 = ">=0.1.3" @@ -1981,6 +2122,7 @@ version = "0.16.12" description = "ruamel.yaml is a YAML parser/emitter that supports roundtrip preservation of comments, seq/map flow style, and map key order" optional = false python-versions = "*" +groups = ["dev"] files = [ {file = "ruamel.yaml-0.16.12-py2.py3-none-any.whl", hash = "sha256:012b9470a0ea06e4e44e99e7920277edf6b46eee0232a04487ea73a7386340a5"}, {file = "ruamel.yaml-0.16.12.tar.gz", hash = "sha256:076cc0bc34f1966d920a49f18b52b6ad559fbe656a0748e3535cf7b3f29ebf9e"}, @@ -1999,6 +2141,8 @@ version = "0.2.8" description = "C version of reader, parser and emitter for ruamel.yaml derived from libyaml" optional = false python-versions = ">=3.6" +groups = ["dev"] +markers = "platform_python_implementation == \"CPython\" and python_version < \"3.9\"" files = [ {file = "ruamel.yaml.clib-0.2.8-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:b42169467c42b692c19cf539c38d4602069d8c1505e97b86387fcf7afb766e1d"}, {file = "ruamel.yaml.clib-0.2.8-cp310-cp310-macosx_13_0_arm64.whl", hash = "sha256:07238db9cbdf8fc1e9de2489a4f68474e70dffcb32232db7c08fa61ca0c7c462"}, @@ -2058,6 +2202,7 @@ version = "0.5.7" description = "An extremely fast Python linter and code formatter, written in Rust." optional = false python-versions = ">=3.7" +groups = ["dev"] files = [ {file = "ruff-0.5.7-py3-none-linux_armv6l.whl", hash = "sha256:548992d342fc404ee2e15a242cdbea4f8e39a52f2e7752d0e4cbe88d2d2f416a"}, {file = "ruff-0.5.7-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:00cc8872331055ee017c4f1071a8a31ca0809ccc0657da1d154a1d2abac5c0be"}, @@ -2085,15 +2230,17 @@ version = "72.2.0" description = "Easily download, build, install, upgrade, and uninstall Python packages" optional = true python-versions = ">=3.8" +groups = ["main"] +markers = "python_full_version >= \"3.12.0\" and extra == \"google\"" files = [ {file = "setuptools-72.2.0-py3-none-any.whl", hash = "sha256:f11dd94b7bae3a156a95ec151f24e4637fb4fa19c878e4d191bfb8b2d82728c4"}, {file = "setuptools-72.2.0.tar.gz", hash = "sha256:80aacbf633704e9c8bfa1d99fa5dd4dc59573efcf9e4042c13d3bcef91ac2ef9"}, ] [package.extras] -core = ["importlib-metadata (>=6)", "importlib-resources (>=5.10.2)", "jaraco.text (>=3.7)", "more-itertools (>=8.8)", "ordered-set (>=3.1.1)", "packaging (>=24)", "platformdirs (>=2.6.2)", "tomli (>=2.0.1)", "wheel (>=0.43.0)"] +core = ["importlib-metadata (>=6) ; python_version < \"3.10\"", "importlib-resources (>=5.10.2) ; python_version < \"3.9\"", "jaraco.text (>=3.7)", "more-itertools (>=8.8)", "ordered-set (>=3.1.1)", "packaging (>=24)", "platformdirs (>=2.6.2)", "tomli (>=2.0.1) ; python_version < \"3.11\"", "wheel (>=0.43.0)"] doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "pyproject-hooks (!=1.1)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier", "towncrier (<24.7)"] -test = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "importlib-metadata", "ini2toml[lite] (>=0.14)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "jaraco.test", "mypy (==1.11.*)", "packaging (>=23.2)", "pip (>=19.1)", "pyproject-hooks (!=1.1)", "pytest (>=6,!=8.1.*)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-home (>=0.5)", "pytest-mypy", "pytest-perf", "pytest-ruff (<0.4)", "pytest-ruff (>=0.2.1)", "pytest-ruff (>=0.3.2)", "pytest-subprocess", "pytest-timeout", "pytest-xdist (>=3)", "tomli", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] +test = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "importlib-metadata", "ini2toml[lite] (>=0.14)", "jaraco.develop (>=7.21) ; python_version >= \"3.9\" and sys_platform != \"cygwin\"", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "jaraco.test", "mypy (==1.11.*)", "packaging (>=23.2)", "pip (>=19.1)", "pyproject-hooks (!=1.1)", "pytest (>=6,!=8.1.*)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-home (>=0.5)", "pytest-mypy", "pytest-perf ; sys_platform != \"cygwin\"", "pytest-ruff (<0.4) ; platform_system == \"Windows\"", "pytest-ruff (>=0.2.1) ; sys_platform != \"cygwin\"", "pytest-ruff (>=0.3.2) ; sys_platform != \"cygwin\"", "pytest-subprocess", "pytest-timeout", "pytest-xdist (>=3)", "tomli", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] [[package]] name = "six" @@ -2101,6 +2248,7 @@ version = "1.16.0" description = "Python 2 and 3 compatibility utilities" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" +groups = ["main"] files = [ {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"}, {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, @@ -2112,6 +2260,8 @@ version = "1.3.1" description = "Sniff out which async library your code is running under" optional = true python-versions = ">=3.7" +groups = ["main"] +markers = "extra == \"notion\"" files = [ {file = "sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2"}, {file = "sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc"}, @@ -2123,6 +2273,8 @@ version = "0.2.7" description = "Next generation python bindings for your taskwarrior database" optional = true python-versions = "<4.0,>=3.8" +groups = ["main"] +markers = "extra == \"tw\"" files = [ {file = "taskw_ng-0.2.7-py3-none-any.whl", hash = "sha256:db956b404b9e992ffe0ad46a7dafea4d591b156fc5dbf009a2a453bfa5a721ea"}, {file = "taskw_ng-0.2.7.tar.gz", hash = "sha256:558942b94b8bcdfa4a4e9c237ca129b37f0f9baeab3608a9b0a70d8f4d499013"}, @@ -2140,6 +2292,7 @@ version = "6.0.0" description = "A wrapper around the stdlib `tokenize` which roundtrips." optional = false python-versions = ">=3.8" +groups = ["dev"] files = [ {file = "tokenize_rt-6.0.0-py2.py3-none-any.whl", hash = "sha256:d4ff7ded2873512938b4f8cbb98c9b07118f01d30ac585a30d7a88353ca36d22"}, {file = "tokenize_rt-6.0.0.tar.gz", hash = "sha256:b9711bdfc51210211137499b5e355d3de5ec88a85d2025c520cbb921b5194367"}, @@ -2151,6 +2304,8 @@ version = "2.0.1" description = "A lil' TOML parser" optional = false python-versions = ">=3.7" +groups = ["dev"] +markers = "python_version < \"3.11\"" files = [ {file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"}, {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"}, @@ -2162,6 +2317,7 @@ version = "0.13.2" description = "Style preserving TOML library" optional = false python-versions = ">=3.8" +groups = ["dev"] files = [ {file = "tomlkit-0.13.2-py3-none-any.whl", hash = "sha256:7a974427f6e119197f670fbbbeae7bef749a6c14e793db934baefc1b5f03efde"}, {file = "tomlkit-0.13.2.tar.gz", hash = "sha256:fff5fe59a87295b278abd31bec92c15d9bc4a06885ab12bcea52c71119392e79"}, @@ -2173,6 +2329,7 @@ version = "4.66.5" description = "Fast, Extensible Progress Meter" optional = false python-versions = ">=3.7" +groups = ["main"] files = [ {file = "tqdm-4.66.5-py3-none-any.whl", hash = "sha256:90279a3770753eafc9194a0364852159802111925aa30eb3f9d85b0e805ac7cd"}, {file = "tqdm-4.66.5.tar.gz", hash = "sha256:e1020aef2e5096702d8a025ac7d16b1577279c9d63f8375b63083e9a5f0fcbad"}, @@ -2193,6 +2350,7 @@ version = "0.22.0.20240310" description = "Typing stubs for httplib2" optional = false python-versions = ">=3.8" +groups = ["dev"] files = [ {file = "types-httplib2-0.22.0.20240310.tar.gz", hash = "sha256:1eda99fea18ec8a1dc1a725ead35b889d0836fec1b11ae6f1fe05440724c1d15"}, {file = "types_httplib2-0.22.0.20240310-py3-none-any.whl", hash = "sha256:8cd706fc81f0da32789a4373a28df6f39e9d5657d1281db4d2fd22ee29e83661"}, @@ -2204,6 +2362,7 @@ version = "5.4.12" description = "Typing stubs for PyYAML" optional = false python-versions = "*" +groups = ["dev"] files = [ {file = "types-PyYAML-5.4.12.tar.gz", hash = "sha256:3f4daa754357491625ae8c3a39c9e1b0d7cd5632bc4e1c35e7a7f75a64aa124b"}, {file = "types_PyYAML-5.4.12-py3-none-any.whl", hash = "sha256:e06083f85375a5678e4c19452ed6467ce2167b71db222313e1792cb8fc76859a"}, @@ -2215,6 +2374,7 @@ version = "57.4.18" description = "Typing stubs for setuptools" optional = false python-versions = "*" +groups = ["dev"] files = [ {file = "types-setuptools-57.4.18.tar.gz", hash = "sha256:8ee03d823fe7fda0bd35faeae33d35cb5c25b497263e6a58b34c4cfd05f40bcf"}, {file = "types_setuptools-57.4.18-py3-none-any.whl", hash = "sha256:9660b8774b12cd61b448e2fd87a667c02e7ec13ce9f15171f1d49a4654c4df6a"}, @@ -2226,10 +2386,12 @@ version = "4.12.2" description = "Backported and Experimental Type Hints for Python 3.8+" optional = false python-versions = ">=3.8" +groups = ["main", "dev"] files = [ {file = "typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d"}, {file = "typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8"}, ] +markers = {main = "python_version < \"3.11\" and extra == \"notion\""} [[package]] name = "tzdata" @@ -2237,6 +2399,8 @@ version = "2024.1" description = "Provider of IANA time zone data" optional = true python-versions = ">=2" +groups = ["main"] +markers = "extra == \"caldav\" and platform_system == \"Windows\"" files = [ {file = "tzdata-2024.1-py2.py3-none-any.whl", hash = "sha256:9068bc196136463f5245e51efda838afa15aaeca9903f49050dfa2679db4d252"}, {file = "tzdata-2024.1.tar.gz", hash = "sha256:2674120f8d891909751c38abcdfd386ac0a5a1127954fbc332af6b5ceae07efd"}, @@ -2248,6 +2412,8 @@ version = "5.2" description = "tzinfo object for the local timezone" optional = true python-versions = ">=3.8" +groups = ["main"] +markers = "extra == \"caldav\"" files = [ {file = "tzlocal-5.2-py3-none-any.whl", hash = "sha256:49816ef2fe65ea8ac19d19aa7a1ae0551c834303d5014c6d5a62e4cbda8047b8"}, {file = "tzlocal-5.2.tar.gz", hash = "sha256:8d399205578f1a9342816409cc1e46a93ebd5755e39ea2d85334bea911bf0e6e"}, @@ -2266,10 +2432,12 @@ version = "4.1.1" description = "Implementation of RFC 6570 URI Templates" optional = false python-versions = ">=3.6" +groups = ["main", "dev"] files = [ {file = "uritemplate-4.1.1-py2.py3-none-any.whl", hash = "sha256:830c08b8d99bdd312ea4ead05994a38e8936266f84b9a7878232db50b044e02e"}, {file = "uritemplate-4.1.1.tar.gz", hash = "sha256:4346edfc5c3b79f694bccd6d6099a322bbeb628dbf2cd86eea55a456ce5124f0"}, ] +markers = {main = "extra == \"google\""} [[package]] name = "urllib3" @@ -2277,14 +2445,16 @@ version = "1.25.11" description = "HTTP library with thread-safe connection pooling, file post, and more." optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <4" +groups = ["main", "dev"] files = [ {file = "urllib3-1.25.11-py2.py3-none-any.whl", hash = "sha256:f5321fbe4bf3fefa0efd0bfe7fb14e90909eb62a48ccda331726b4319897dd5e"}, {file = "urllib3-1.25.11.tar.gz", hash = "sha256:8d7eaa5a82a1cac232164990f04874c594c9453ec55eef02eab885aa02fc17a2"}, ] +markers = {main = "python_version <= \"3.11\" and (extra == \"gkeep\" or extra == \"google\" or extra == \"asana\" or extra == \"caldav\")", dev = "python_version <= \"3.11\""} [package.extras] brotli = ["brotlipy (>=0.6.0)"] -secure = ["certifi", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "ipaddress", "pyOpenSSL (>=0.14)"] +secure = ["certifi", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "ipaddress ; python_version == \"2.7\"", "pyOpenSSL (>=0.14)"] socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"] [[package]] @@ -2293,14 +2463,16 @@ version = "1.26.19" description = "HTTP library with thread-safe connection pooling, file post, and more." optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7" +groups = ["main", "dev"] files = [ {file = "urllib3-1.26.19-py2.py3-none-any.whl", hash = "sha256:37a0344459b199fce0e80b0d3569837ec6b6937435c5244e7fd73fa6006830f3"}, {file = "urllib3-1.26.19.tar.gz", hash = "sha256:3e3d753a8618b86d7de333b4223005f68720bcd6a7d2bcb9fbd2229ec7c1e429"}, ] +markers = {main = "python_full_version > \"3.12.0\" and (extra == \"gkeep\" or extra == \"google\" or extra == \"asana\" or extra == \"caldav\")", dev = "python_full_version > \"3.12.0\""} [package.extras] -brotli = ["brotli (==1.0.9)", "brotli (>=1.0.9)", "brotlicffi (>=0.8.0)", "brotlipy (>=0.6.0)"] -secure = ["certifi", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "ipaddress", "pyOpenSSL (>=0.14)", "urllib3-secure-extra"] +brotli = ["brotli (==1.0.9) ; os_name != \"nt\" and python_version < \"3\" and platform_python_implementation == \"CPython\"", "brotli (>=1.0.9) ; python_version >= \"3\" and platform_python_implementation == \"CPython\"", "brotlicffi (>=0.8.0) ; (os_name != \"nt\" or python_version >= \"3\") and platform_python_implementation != \"CPython\"", "brotlipy (>=0.6.0) ; os_name == \"nt\" and python_version < \"3\""] +secure = ["certifi", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "ipaddress ; python_version == \"2.7\"", "pyOpenSSL (>=0.14)", "urllib3-secure-extra"] socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"] [[package]] @@ -2309,13 +2481,15 @@ version = "2.2.2" description = "HTTP library with thread-safe connection pooling, file post, and more." optional = false python-versions = ">=3.8" +groups = ["main", "dev"] files = [ {file = "urllib3-2.2.2-py3-none-any.whl", hash = "sha256:a448b2f64d686155468037e1ace9f2d2199776e17f0a46610480d311f73e3472"}, {file = "urllib3-2.2.2.tar.gz", hash = "sha256:dd505485549a7a552833da5e6063639d0d177c04f23bc3864e41e5dc5f612168"}, ] +markers = {main = "python_full_version == \"3.12.0\" and (extra == \"google\" or extra == \"asana\" or extra == \"caldav\")", dev = "python_full_version == \"3.12.0\""} [package.extras] -brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)"] +brotli = ["brotli (>=1.0.9) ; platform_python_implementation == \"CPython\"", "brotlicffi (>=0.8.0) ; platform_python_implementation != \"CPython\""] h2 = ["h2 (>=4,<5)"] socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"] zstd = ["zstandard (>=0.18.0)"] @@ -2326,6 +2500,7 @@ version = "20.26.3" description = "Virtual Python Environment builder" optional = false python-versions = ">=3.7" +groups = ["dev"] files = [ {file = "virtualenv-20.26.3-py3-none-any.whl", hash = "sha256:8cc4a31139e796e9a7de2cd5cf2489de1217193116a8fd42328f1bd65f434589"}, {file = "virtualenv-20.26.3.tar.gz", hash = "sha256:4c43a2a236279d9ea36a0d76f98d84bd6ca94ac4e0f4a3b9d46d05e10fea542a"}, @@ -2338,7 +2513,7 @@ platformdirs = ">=3.9.1,<5" [package.extras] docs = ["furo (>=2023.7.26)", "proselint (>=0.13)", "sphinx (>=7.1.2,!=7.3)", "sphinx-argparse (>=0.4)", "sphinxcontrib-towncrier (>=0.2.1a0)", "towncrier (>=23.6)"] -test = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "coverage-enable-subprocess (>=1)", "flaky (>=3.7)", "packaging (>=23.1)", "pytest (>=7.4)", "pytest-env (>=0.8.2)", "pytest-freezer (>=0.4.8)", "pytest-mock (>=3.11.1)", "pytest-randomly (>=3.12)", "pytest-timeout (>=2.1)", "setuptools (>=68)", "time-machine (>=2.10)"] +test = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "coverage-enable-subprocess (>=1)", "flaky (>=3.7)", "packaging (>=23.1)", "pytest (>=7.4)", "pytest-env (>=0.8.2)", "pytest-freezer (>=0.4.8) ; platform_python_implementation == \"PyPy\" or platform_python_implementation == \"CPython\" and sys_platform == \"win32\" and python_version >= \"3.13\"", "pytest-mock (>=3.11.1)", "pytest-randomly (>=3.12)", "pytest-timeout (>=2.1)", "setuptools (>=68)", "time-machine (>=2.10) ; platform_python_implementation == \"CPython\""] [[package]] name = "vobject" @@ -2346,6 +2521,8 @@ version = "0.9.7" description = "A full-featured Python package for parsing and creating iCalendar and vCard files" optional = true python-versions = "*" +groups = ["main"] +markers = "extra == \"caldav\"" files = [ {file = "vobject-0.9.7-py2.py3-none-any.whl", hash = "sha256:67ebec81ee39fc60b7355ce077f850d5f13d99d08b110fa1abcfdbb516205e20"}, {file = "vobject-0.9.7.tar.gz", hash = "sha256:ab727bf81de88984ada5c11f066f1e1649903d3e3d7ec91f1ce968172afd5256"}, @@ -2360,13 +2537,15 @@ version = "1.1.0" description = "A small Python utility to set file creation time on Windows" optional = false python-versions = ">=3.5" +groups = ["main"] +markers = "sys_platform == \"win32\"" files = [ {file = "win32_setctime-1.1.0-py3-none-any.whl", hash = "sha256:231db239e959c2fe7eb1d7dc129f11172354f98361c4fa2d6d2d7e278baa8aad"}, {file = "win32_setctime-1.1.0.tar.gz", hash = "sha256:15cf5750465118d6929ae4de4eb46e8edae9a5634350c01ba582df868e932cb2"}, ] [package.extras] -dev = ["black (>=19.3b0)", "pytest (>=4.6.2)"] +dev = ["black (>=19.3b0) ; python_version >= \"3.6\"", "pytest (>=4.6.2)"] [[package]] name = "wrapt" @@ -2374,6 +2553,7 @@ version = "1.16.0" description = "Module for decorators, wrappers and monkey patching." optional = false python-versions = ">=3.6" +groups = ["dev"] files = [ {file = "wrapt-1.16.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ffa565331890b90056c01db69c0fe634a776f8019c143a5ae265f9c6bc4bd6d4"}, {file = "wrapt-1.16.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e4fdb9275308292e880dcbeb12546df7f3e0f96c6b41197e0cf37d2826359020"}, @@ -2453,6 +2633,8 @@ version = "0.0.7" description = "A Python module and program to convert calendars using X-WR-TIMEZONE to standard ones." optional = true python-versions = "*" +groups = ["main"] +markers = "extra == \"caldav\"" files = [ {file = "x_wr_timezone-0.0.7-py3-none-any.whl", hash = "sha256:0b5e16f677c8f51ce41087a0b3d4f786c5fdcf78af4f8a75d4d960107dcb6d3a"}, {file = "x_wr_timezone-0.0.7.tar.gz", hash = "sha256:ccbaae164a52086535fd2eb1dced164a5250acc83a672fbb044d11e81a268965"}, @@ -2468,6 +2650,8 @@ version = "0.9.9" description = "Python wrapper for extended filesystem attributes" optional = true python-versions = "*" +groups = ["main"] +markers = "extra == \"fs\"" files = [ {file = "xattr-0.9.9-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:58a9fb4fd19b467e88f4b75b5243706caa57e312d3aee757b53b57c7fd0f4ba9"}, {file = "xattr-0.9.9-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:e71efca59705c7abde5b7f76323ebe00ed2977f10cba4204b9421dada036b5ca"}, @@ -2535,6 +2719,8 @@ version = "6.0.0" description = "Variables defined by the XDG Base Directory Specification" optional = true python-versions = ">=3.7,<4.0" +groups = ["main"] +markers = "extra == \"tw\"" files = [ {file = "xdg-6.0.0-py3-none-any.whl", hash = "sha256:df3510755b4395157fc04fc3b02467c777f3b3ca383257397f09ab0d4c16f936"}, {file = "xdg-6.0.0.tar.gz", hash = "sha256:24278094f2d45e846d1eb28a2ebb92d7b67fc0cab5249ee3ce88c95f649a1c92"}, @@ -2546,6 +2732,8 @@ version = "3.20.0" description = "Backport of pathlib-compatible object wrapper for zip files" optional = false python-versions = ">=3.8" +groups = ["dev"] +markers = "python_version < \"3.9\"" files = [ {file = "zipp-3.20.0-py3-none-any.whl", hash = "sha256:58da6168be89f0be59beb194da1250516fdaa062ccebd30127ac65d30045e10d"}, {file = "zipp-3.20.0.tar.gz", hash = "sha256:0145e43d89664cfe1a2e533adc75adafed82fe2da404b4bbb6b026c0157bdb31"}, @@ -2553,7 +2741,7 @@ files = [ [package.extras] doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] -test = ["big-O", "importlib-resources", "jaraco.functools", "jaraco.itertools", "jaraco.test", "more-itertools", "pytest (>=6,!=8.1.*)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-ignore-flaky", "pytest-mypy", "pytest-ruff (>=0.2.1)"] +test = ["big-O", "importlib-resources ; python_version < \"3.9\"", "jaraco.functools", "jaraco.itertools", "jaraco.test", "more-itertools", "pytest (>=6,!=8.1.*)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-ignore-flaky", "pytest-mypy", "pytest-ruff (>=0.2.1) ; sys_platform != \"cygwin\""] [extras] asana = ["asana"] @@ -2565,6 +2753,6 @@ notion = ["notion-client"] tw = ["taskw-ng", "xdg"] [metadata] -lock-version = "2.0" -python-versions = ">=3.8.1,<=3.12.5" -content-hash = "eba5002826c17b8831db5486299b466f8673c50f5bc900d8d3dcfe6530eb510b" +lock-version = "2.1" +python-versions = ">=3.8.1,<=3.15.5" +content-hash = "6bc7b217926bec647f97e9591d0ae4d536ca5bedbf82dee9956486dfe83c8e30" diff --git a/pyproject.toml b/pyproject.toml index 1c35133..d90f0c9 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -49,10 +49,11 @@ tw_notion_sync = "syncall.scripts.tw_notion_sync:main" fs_gkeep_sync = "syncall.scripts.fs_gkeep_sync:main" tw_caldav_sync = "syncall.scripts.tw_caldav_sync:main" tw_gtasks_sync = "syncall.scripts.tw_gtasks_sync:main" +tw_cattr_sync = "syncall.scripts.tw_cattr_sync:main" # end-user dependencies -------------------------------------------------------- [tool.poetry.dependencies] -python = ">=3.8.1,<=3.12.5" +python = ">=3.8.1,<=3.15.5" PyYAML = "~5.3.1" bidict = "^0.21.4" diff --git a/syncall/cattr/cattr_side.py b/syncall/cattr/cattr_side.py new file mode 100644 index 0000000..7e369de --- /dev/null +++ b/syncall/cattr/cattr_side.py @@ -0,0 +1,186 @@ +import os +import requests +import http.client as http_client +import logging +import json + +from syncall.cattr.cattr_task import CattrTask +from syncall.sync_side import SyncSide +from typing import Optional, Sequence +from xdg import xdg_config_home +from pathlib import Path + +http_client.HTTPConnection.debuglevel = 1 + +# You must initialize logging, otherwise you'll not see debug output. +logging.basicConfig() +logging.getLogger().setLevel(logging.DEBUG) +requests_log = logging.getLogger("requests.packages.urllib3") +requests_log.setLevel(logging.DEBUG) +requests_log.propagate = True +cattr_config_file=Path().joinpath(xdg_config_home(),'syncall','cattr.json') +if cattr_config_file.exists(): + with open(cattr_config_file,'r') as f: + self.cattr_config=json.load(f) + +class CattrSide(SyncSide): + def __init__(self): + self.headers={"Authorization":os.getenv("CATTR_TOKEN","Bearer Foo")} + self.api=os.getenv("CATTR_URL") + self.tasks={} + self.users={} + self.projects={} + self.dirty=[] + super().__init__(name="Cattr", fullname="Cattr") + def start(self): + """Initialization steps. + + Call this manually. Derived classes can take care of setting up data + structures / connection, authentication requests etc. + """ + self.get_all_users() + self.get_all_projects() + + def finish(self): + """Finalization steps. + + Call this manually. Derived classes can take care of closing open connections, flashing + their cached data, etc. + """ + def get_all_projects(self): + t=requests.post(self.api+"projects/list",headers=self.headers) + prj=t.json()["data"] + for u in prj: + self.projects[u['name']]={"id":u['id']} + def get_project(self,name): + return self.projects[name] + def get_project_id(self,name): + if name in self.projects: + return self.projects[name]['id'] + else: + assert 0,f"Project {name} not on server {self.projects}" + return 1 + + def get_all_users(self): + t=requests.post(self.api+"users/list",headers=self.headers) + users=t.json()["data"] + for u in users: + self.users[u['full_name']]={"id":u['id'],"email":u["email"]} + def get_user(self,name): + return self.users[name] + + + + def get_all_items(self, **kargs) -> Sequence[CattrTask]: + t=requests.post(self.api+"tasks/list",headers=self.headers) + tasks=t.json()["data"] + results=[] + for t in tasks: + self.tasks[t["id"]]=t + results.append(CattrTask.from_json(t)) + """Query side and return a sequence of items + + :param kargs: Extra options for the call + :return: A list of items. The type of these items depends on the derived class + """ + return results + + def get_item(self, item_id: str, use_cached: bool = False) -> Optional[CattrTask]: + """Get a single item based on the given UUID. + + :use_cached: False if you want to fetch the latest version of the item. True if a + cached version would do. + :returns: None if not found, the item in dict representation otherwise + """ + if use_cached: + return CattrTask.from_json(self.tasks[item_id]) + + self.get_all_items() + return CattrTask.from_json(self.tasks[int(item_id)]) + + def delete_single_item(self, item_id: str): + """Delete an item based on the given UUID. + + .. raises:: Keyerror if item is not found. + """ + requests.post(self.api+"tasks/remove",headers=self.headers,payload={"id":item_id}) + del self.tasks[item_id] + + + def update_item(self, item_id: str, **changes): + """Update with the given item. + + :param item_id : ID of item to update + :param changes: Keyword only parameters that are to change in the item + .. warning:: The item must already be present + """ + edit_task=None + requests_log.info(changes) + for id,task in self.tasks.items(): + if task["id"] == item_id: + for k,v in changes: + task[k]= v + self.dirty.append(task["id"]) + edit_task=task + break + + if edit_task is not None: + requests.post(self.api+"tasks/edit",headers=self.headers,params={ + "id":item_id, + "project_id":get_project_id(edit_task.get("project_name"," ")), + "active":task["status_id"]!=2, + "priority_id":1, + }) + + def get_mapped_users(self,task): + users=[] + if 'tags' in task: + for name,u in self.users.items(): + if name in task['tags']: + users.append(u['id']) + return users + def add_item(self, item: CattrTask) -> CattrTask: + """Add a new item". + + :returns: The newly added event + """ + r=requests.post(self.api+"tasks/create",headers=self.headers,params={ + "start_date":item.start_date, + "due_date":item.due_date, + #'users':[1,2], + "project_id":self.get_project_id(item.project_name), + "task_name":item.task_name, + "description":"todo", + "important":1, + "priority_id":1, + "status_id":1, + }) + return CattrTask.from_json(r.json()["data"]) + + @classmethod + def id_key(cls) -> str: + """Key in the dictionary of the added/updated/deleted item that refers to the ID of + that Item. + """ + return "id" + + @classmethod + def summary_key(cls) -> str: + """Key in the dictionary of the item that refers to its summary.""" + return "task_name" + + @classmethod + def last_modification_key(cls) -> str: + """Key in the dictionary of the item that refers to its modification date.""" + return "updated_at" + + @classmethod + def items_are_identical( + cls, item1: CattrTask, item2: CattrTask, ignore_keys: Sequence[str] = [], + ) -> bool: + """Determine whether two items are identical. + + .. returns:: True if items are identical, False otherwise. + """ + compare_keys=["project_id","task_name"] + return SyncSide._items_are_identical(item1,item2,compare_keys) diff --git a/syncall/cattr/cattr_task.py b/syncall/cattr/cattr_task.py new file mode 100644 index 0000000..c403beb --- /dev/null +++ b/syncall/cattr/cattr_task.py @@ -0,0 +1,80 @@ +import datetime +from dataclasses import dataclass +from typing import TYPE_CHECKING, Any, Mapping + +@dataclass +class CattrTask(Mapping): + """Represents a Cattr Task.""" + start_date: str + due_date : str + users:list[int] + project_phase_id: int + project_id:int + task_name:str + description :str + important:bool + priority_id :int + status_id :int + ## + url: str + project_name: str + id:int + assigned_by:int + created_at:str + updated_at:str + deleted_at:str + relative_position:int + estimate:int + _key_names: frozenset[str]=frozenset({ + "start_date", + "due_date", + "users", + "project_phase_id", + "project_id", + "task_name", + "description", + "important", + "priority_id", + "status_id", + "url", + "project_name", + "id", + "assigned_by", + "created_at", + "updated_at", + "deleted_at", + "relative_position", + "estimate", + },) + + def __getitem__(self, key) -> Any: # noqa: ANN401 + return getattr(self, key) + + def __iter__(self): + yield from self._key_names + + def __len__(self): + return len(self._key_names) + @classmethod + def from_json(cls,jsn): # -> CattrTask: + return CattrTask( + start_date = jsn.get("start_date",datetime.datetime.today()), + due_date = jsn.get("due_date",datetime.datetime.today()), + users = jsn.get("users",None), + project_phase_id = jsn.get("project_phase_id",None), + project_id = jsn.get("project_id",None), + task_name = jsn.get("task_name",None), + description = jsn.get("description","todo"), + important = jsn.get("important",None), + priority_id = jsn.get("priority_id",None), + status_id = jsn.get("status_id",None), + url = jsn.get("url",None), + project_name = jsn.get("project_name","default"), + id = jsn.get("id",None), + assigned_by = jsn.get("assigned_by",None), + created_at = jsn.get("created_at",None), + updated_at = jsn.get("updated_at",None), + deleted_at = jsn.get("deleted_at",None), + relative_position = jsn.get("relative_position",None), + estimate = jsn.get("estimate",None), + ) diff --git a/syncall/cli.py b/syncall/cli.py index 50c89df..34c0d58 100644 --- a/syncall/cli.py +++ b/syncall/cli.py @@ -44,6 +44,120 @@ def _opt_pdb_on_error(): ) +# cattr related options ----------------------------------------------------------------------- +def opts_cattr(hidden_gid: bool): + print("test") + def decorator(f): + for d in reversed([ + _opt_cattr_task_gid, + _opt_cattr_token_pass_path, + _opt_cattr_url_path, + ],): + f=d()(f) + return _opt_cattr_task_gid(hidden=hidden_gid)(f) + return decorator + +def _opt_cattr_task_gid(**kwargs): + return click.option( + "-a", + "--cattr-task-gid", + "cattr_task_gid", + type=str, + help="Limit sync to provided task", + **kwargs, + ) + + +def _opt_cattr_url_path(): + def callback(ctx, param, value): + del ctx + + # fetch API token to connect to cattr ------------------------------------------------- + cattr_url = os.environ.get("CATTR_URL") + + if cattr_url is None: + error_and_exit( + "You must provide an Cattr Personal Access cattr_url, using the" + f" {'/'.join(param.opts)} option", + ) + if cattr_url is not None: + logger.debug( + "Reading the Cattr Personal Access cattr_url (PAT) from environment" + " variable...", + ) + + return cattr_url + + return click.option( + "--url", + "--url-path", + "cattr_url", + help="URL of cattr API", + expose_value=True, + callback=callback, + ) +def _opt_cattr_token_pass_path(): + def callback(ctx, param, value): + del ctx + + api_token_pass_path = value + + # fetch API token to connect to cattr ------------------------------------------------- + cattr_token = os.environ.get("CATTR_PERSONAL_ACCESS_TOKEN") + + if cattr_token is None and api_token_pass_path is None: + error_and_exit( + "You must provide an Cattr Personal Access cattr_token, using the" + f" {'/'.join(param.opts)} option", + ) + if cattr_token is not None: + logger.debug( + "Reading the Cattr Personal Access cattr_token (PAT) from environment" + " variable...", + ) + else: + cattr_token = fetch_from_pass_manager(api_token_pass_path) + + return cattr_token + + return click.option( + "--token", + "--token-pass-path", + "cattr_token", + help="Path in the UNIX password manager to fetch", + expose_value=True, + callback=callback, + ) + + +def _opt_cattr_workspace_gid(): + return click.option( + "-w", + "--cattr-workspace-gid", + "cattr_workspace_gid", + type=str, + help="Cattr workspace GID used to filter tasks", + ) + + +def _opt_cattr_workspace_name(): + return click.option( + "-W", + "--cattr-workspace-name", + "cattr_workspace_name", + type=str, + help="Cattr workspace name used to filter tasks", + ) + + +def _opt_list_cattr_workspaces(): + return click.option( + "--list-cattr-workspaces", + "do_list_cattr_workspaces", + is_flag=True, + help="List the available Cattr workspaces", + ) + # asana related options ----------------------------------------------------------------------- def opts_asana(hidden_gid: bool): def decorator(f): diff --git a/syncall/scripts/tw_cattr_sync.py b/syncall/scripts/tw_cattr_sync.py new file mode 100644 index 0000000..ff7797e --- /dev/null +++ b/syncall/scripts/tw_cattr_sync.py @@ -0,0 +1,238 @@ +from __future__ import annotations + +import sys + +#import cattr +import click +from bubop import ( + check_optional_mutually_exclusive, + check_required_mutually_exclusive, + format_dict, + logger, + loguru_tqdm_sink, +) + +from syncall.app_utils import confirm_before_proceeding, inform_about_app_extras + +try: + from syncall.cattr.cattr_side import CattrSide + from syncall.taskwarrior.taskwarrior_side import TaskWarriorSide +except ImportError: + inform_about_app_extras(["Cattr", "tw"]) + + +from syncall.aggregator import Aggregator +from syncall.app_utils import ( + app_log_to_syslog, + cache_or_reuse_cached_combination, + error_and_exit, + fetch_app_configuration, + get_resolution_strategy, + register_teardown_handler, +) +from syncall.cli import opts_cattr,opts_miscellaneous, opts_tw_filtering +from syncall.tw_cattr_utils import convert_cattr_to_tw, convert_tw_to_cattr + + +# CLI parsing --------------------------------------------------------------------------------- +@click.command() +@opts_cattr(hidden_gid=False) +@opts_tw_filtering() +@opts_miscellaneous("TW", "Cattr") +def main( # noqa: PLR0915, C901, PLR0912 + cattr_task_gid:str, + # cattr_token:str, + cattr_url:str, + tw_filter: str, + tw_tags: list[str], + tw_project: str, + tw_only_modified_last_X_days: str, + tw_sync_all_tasks: bool, + prefer_scheduled_date: bool, + resolution_strategy: str, + verbose: int, + combination_name: str, + custom_combination_savename: str, + pdb_on_error: bool, + confirm: bool, +): + """Synchronize your tasks in Cattr with filters from Taskwarrior.""" + del prefer_scheduled_date + + loguru_tqdm_sink(verbosity=verbose) + app_log_to_syslog() + logger.debug("Initialising...") + inform_about_config = False + + # cli validation -------------------------------------------------------------------------- + check_optional_mutually_exclusive(combination_name, custom_combination_savename) + + tw_filter_li = [ + t + for t in [ + tw_filter, + tw_only_modified_last_X_days, + ] + if t + ] + + # combination_of_tw_filters_and_asana_workspace = any( + # [ + # tw_filter_li, + # tw_tags, + # tw_project, + # tw_sync_all_tasks, + # asana_workspace_gid, + # asana_workspace_name, + # ], + # ) + # check_optional_mutually_exclusive( + # combination_name, + # combination_of_tw_filters_and_asana_workspace, + # ) + + # existing combination name is provided --------------------------------------------------- + if combination_name is not None: + app_config = fetch_app_configuration( + side_A_name="Taskwarrior", + side_B_name="Cattr", + combination=combination_name, + ) + tw_tags = app_config["tw_tags"] + tw_project = app_config["tw_project"] + tw_sync_all_tasks = app_config["tw_sync_all_tasks"] + cattr_task_gid = app_config["cattr_task_gid"] + # combination manually specified ---------------------------------------------------------- + else: + inform_about_config = True + combination_name = cache_or_reuse_cached_combination( + config_args={ + "tw_project": tw_project, + "tw_tags": tw_tags, + "cattr_task_gid": cattr_task_gid, + }, + config_fname="tw_cattr_configs", + custom_combination_savename=custom_combination_savename, + ) + + # initialize cattr ----------------------------------------------------------------------- + #asana_client = asana.Client.access_token(asana_token) + #asana_client.headers["Asana-Disable"] = ",".join( + # [ + # asana_client.headers.get("Asana-Disable", ""), + # "new_user_task_lists", + # "new_goal_memberships", + # ], + #) + #asana_client.options["client_name"] = "syncall" + + ## list workspaces and exit + #if do_list_asana_workspaces: + # list_asana_workspaces(asana_client) + # return 0 + + # asana workspaces------------------------------------------------------------------------- + # Validate Asana workspace selection. Skip this only if we are going to + # --list-asana-workspaces or if --asana-task-gid was not specified. + # if cattr_task_gid is None: + # if asana_workspace_gid is None: + # if asana_workspace_name is None: + # error_and_exit("Provide either an Asana workspace name or GID to sync.") + # elif asana_workspace_name is not None: + # error_and_exit("Provide either Asana workspace GID or name, but not both.") + + # found_workspace = False + + # for workspace in asana_client.workspaces.find_all(): # type: ignore + # if workspace["gid"] == asana_workspace_gid: + # asana_workspace_name = workspace["name"] + # found_workspace = True + # break + # if workspace["name"] == asana_workspace_name: + # if found_workspace: + # error_and_exit( + # f"Found multiple workspaces with name {asana_workspace_name}. Please" + # " specify workspace GID instead.", + # ) + # else: + # asana_workspace_gid = workspace["gid"] + # found_workspace = True + # else: + # if not asana_workspace_gid: + # li = [f"No Asana workspace was found with GID {asana_workspace_gid}"] + # if asana_workspace_name: + # li.append(f" | Workspace Name: {asana_workspace_name}") + # error_and_exit(f"{' '.join(li)}.") + + # # more checks ----------------------------------------------------------------------------- + # combination_of_tw_related_options = any([tw_filter_li, tw_tags, tw_project]) + # check_required_mutually_exclusive( + # tw_sync_all_tasks, + # combination_of_tw_related_options, + # "sync_all_tw_tasks", + # "combination of specific TW-related options", + # ) + + # # announce configuration ------------------------------------------------------------------ + logger.info( + format_dict( + header="Configuration", + items={ + "TW Filter": " ".join(tw_filter_li), + "TW Tags": tw_tags, + "TW Project": tw_project, + "TW Sync All Tasks": tw_sync_all_tasks, + "Cattr Task GID": cattr_task_gid, + }, + prefix="\n\n", + suffix="\n", + ), + ) + if confirm: + confirm_before_proceeding() + + # initialize sides ------------------------------------------------------------------------ + tw_side = TaskWarriorSide( + tw_filter=" ".join(tw_filter_li), + tags=tw_tags, + project=tw_project, + ) + + cattr_side = CattrSide() + + # teardown function and exception handling ------------------------------------------------ + register_teardown_handler( + pdb_on_error=pdb_on_error, + inform_about_config=inform_about_config, + combination_name=combination_name, + verbose=verbose, + ) + + # sync ------------------------------------------------------------------------------------ + with Aggregator( + side_A=cattr_side, + side_B=tw_side, + converter_A_to_B=convert_cattr_to_tw, + converter_B_to_A=convert_tw_to_cattr, + resolution_strategy=get_resolution_strategy( + resolution_strategy, + side_A_type=type(cattr_side), + side_B_type=type(tw_side), + ), + config_fname=combination_name, + ignore_keys=( + ( + "completed_at", + "created_at", + "modified_at", + ), + ("end", "entry", "modified", "urgency"), + ), + ) as aggregator: + aggregator.sync() + + return 0 + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/syncall/tw_cattr_utils.py b/syncall/tw_cattr_utils.py new file mode 100644 index 0000000..7b4c132 --- /dev/null +++ b/syncall/tw_cattr_utils.py @@ -0,0 +1,161 @@ +"""Asana-related utils.""" +import datetime +import logging + +from bubop import parse_datetime + +from syncall.cattr.cattr_task import CattrTask +from syncall.types import TwItem + +logger = logging.getLogger(__name__) + +def convert_tw_to_cattr(tw_item: TwItem) -> CattrTask: + # Extract Taskwarrior fields + logger.info(tw_item) + with open("log.log","w") as f: + print(tw_item,file=f) + tw_description = tw_item["description"] + tw_due = None + if "due" in tw_item: + tw_due = tw_item["due"] + tw_end = None + if "end" in tw_item: + tw_end = tw_item["end"] + tw_entry = tw_item["entry"] + tw_modified = tw_item["modified"] + tw_status = tw_item["status"] + + # Declare Cattr fields + start_date = None + due_date = None + users = None + project_phasae_id = None + project_id = None + task_name = tw_item['description'] + description = None + important=False + priority_id=None + status_id=None + project_name=tw_item.get("project", None) + + + # Convert Taskwarrior fields to Asana fields + if tw_status == "completed": + status_id = 2 + + if tw_end is not None: + if isinstance(tw_end, datetime.datetime): + as_completed_at = tw_end + else: + as_completed_at = parse_datetime(tw_end) + + if not isinstance(tw_entry, datetime.datetime): + as_created_at = parse_datetime(tw_entry) + else: + as_created_at = tw_entry + + if tw_due is not None: + date = tw_due if isinstance(tw_due, datetime.datetime) else parse_datetime(tw_due) + due_date=date.strftime("%Y-%m-%d") + task_name = tw_description + + # Build Cattr task + ct = CattrTask( + start_date=start_date, + due_date=due_date, + task_name=task_name, + project_name=project_name, + url=tw_item["uuid"], + users=None, + project_phase_id=None, + project_id=None, + description=None, + important=None, + priority_id=None, + status_id=status_id, + id=None, + assigned_by=None, + created_at=None, + updated_at=None, + deleted_at=None, + relative_position=None, + estimate=None, + ) + print(ct) + return ct + + +def convert_cattr_to_tw(cattr_task: CattrTask) -> TwItem: # noqa: PLR0912 + logger.info("Hello") + # Extract Cattr fields + ct_completed = cattr_task["status_id"]==2 + ct_completed_at = cattr_task["deleted_at"] + ct_completed_on=None + ct_created_at = cattr_task["created_at"] + ct_due_at = cattr_task["due_date"] + ct_modified_at = cattr_task["updated_at"] + ct_name = cattr_task["task_name"] + + # Declare Taskwarrior fields + tw_due = None + tw_end = None + tw_entry = None + tw_modified = None + tw_status = "pending" + + # Convert Asana fields to Taskwarrior fields + if isinstance(ct_created_at, datetime.datetime): + tw_entry = ct_created_at + else: + tw_entry = parse_datetime(ct_created_at) + + if ct_completed and cattr_task['deleted_at']: + if isinstance(ct_completed_at, datetime.datetime): + tw_end = ct_completed_at + else: + tw_end = parse_datetime(ct_completed_at) + tw_status = "completed" + + if ct_modified_at is not None: + if isinstance(ct_modified_at, datetime.datetime): + tw_modified = ct_modified_at + else: + tw_modified = parse_datetime(ct_modified_at) + + # Asana may give us either 'due_at' (contains time and zone) or 'due_on' + # (contains neither). + if ct_due_at is not None: + if isinstance(ct_due_at, datetime.datetime): + tw_due = ct_due_at + else: + tw_due = parse_datetime(ct_due_at) + + tw_description = ct_name + + tw_task = { + "description": tw_description, + "due": None, + "end": tw_end, + "entry": tw_entry, + "modified": tw_modified, + "status": tw_status, + } + logger.info(tw_task) + + try: + if tw_due is not None: + tw_task["due"] = tw_due + + if tw_modified is not None: + tw_task["modified"] = tw_modified + + except Exception as err: + print(cattr_task,Exception, err) + return { + "description": tw_description, + "due": tw_due, + "end": tw_end, + "entry": tw_entry, + "modified": tw_modified, + "status": tw_status, + }