diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b9d22a1 --- /dev/null +++ b/.gitignore @@ -0,0 +1,168 @@ +# Created by .ignore support plugin (hsz.mobi) +### Python template +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +.hypothesis/ +.pytest_cache/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# pyenv +.python-version + +# celery beat schedule file +celerybeat-schedule + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +### JetBrains template +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm +# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 + +# User-specific stuff +.idea/**/workspace.xml +.idea/**/tasks.xml +.idea/**/usage.statistics.xml +.idea/**/dictionaries +.idea/**/shelf + +# Sensitive or high-churn files +.idea/**/dataSources/ +.idea/**/dataSources.ids +.idea/**/dataSources.local.xml +.idea/**/sqlDataSources.xml +.idea/**/dynamic.xml +.idea/**/uiDesigner.xml +.idea/**/dbnavigator.xml + +# Gradle +.idea/**/gradle.xml +.idea/**/libraries + +# Gradle and Maven with auto-import +# When using Gradle or Maven with auto-import, you should exclude module files, +# since they will be recreated, and may cause churn. Uncomment if using +# auto-import. +# .idea/modules.xml +# .idea/*.iml +# .idea/modules + +# CMake +cmake-build-*/ + +# Mongo Explorer plugin +.idea/**/mongoSettings.xml + +# File-based project format +*.iws + +# IntelliJ +out/ + +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Cursive Clojure plugin +.idea/replstate.xml + +# Crashlytics plugin (for Android Studio and IntelliJ) +com_crashlytics_export_strings.xml +crashlytics.properties +crashlytics-build.properties +fabric.properties + +# Editor-based Rest Client +.idea/httpRequests + diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..73637bd --- /dev/null +++ b/requirements.txt @@ -0,0 +1 @@ +httplib2 \ No newline at end of file diff --git a/rtmapi/__init__.py b/rtmapi/__init__.py index 8f93cdb..5665cce 100644 --- a/rtmapi/__init__.py +++ b/rtmapi/__init__.py @@ -1,13 +1,50 @@ +# Copyright (c) 2019 Giacomo Lacava, TarGLet Limited +# Copyright (c) 2017 Tom Matheussen +# Copyright (c) 2010 Michael Gruenewald +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. +# + import hashlib import httplib2 +import logging import urllib.request, urllib.parse, urllib.error import xml.etree.ElementTree as ElementTree import json -__author__ = "Michael Gruenewald " +__author__ = "Michael Gruenewald ,\n" \ + "Giacomo Lacava ,\n" \ + "Tom Matheussen " __all__ = ('Rtm', 'RtmException') +def _anonimize_url(url): + parsedurl = urllib.parse.urlparse(url) + qs = urllib.parse.parse_qs(parsedurl.query) + for param in ('api_key', 'auth_token', 'api_sig'): + if param in qs: + qs[param] = '...' + rejoined = "&".join([key + '=' + "".join(value) for key, value in qs.items()]) + parsedurl = parsedurl._replace(query=rejoined) + return urllib.parse.urlunparse(parsedurl) + + class RtmException(Exception): pass @@ -100,7 +137,7 @@ def _call_method(self, method_name, **params): "Request %s failed (HTTP). Status: %s, reason: %s" % ( method_name, infos.status, infos.reason)) - if (params['format'] and params['format'] == 'json'): + if params.get('format', 'xml') == 'json': json_obj = json.loads(data.decode("utf-8")) return json_obj['rsp'] @@ -120,6 +157,7 @@ def _call_method_auth(self, method_name, **params): def _make_request(self, request_url=None, **params): final_url = self._make_request_url(request_url, **params) + logging.debug(_anonimize_url(final_url)) return self.http.request(final_url, headers={ 'Cache-Control': 'no-cache, max-age=0'}) @@ -166,6 +204,7 @@ class RtmBase(object): "participants": "participant", "tags": "tag", "timezones": "timezone", + "lists": "list" } @classmethod