diff options
author | Tobias Brox <tobias@redpill-linpro.com> | 2021-02-05 12:33:39 +0100 |
---|---|---|
committer | Tobias Brox <tobias@redpill-linpro.com> | 2021-02-05 12:33:39 +0100 |
commit | 60ec379725b3ffedf57f33e869b15a4abf09464d (patch) | |
tree | 1633ef05f5c7fba224a137b30f722c072772646c | |
parent | e5968d0faa6852440f27ea23778a96814bef95fd (diff) | |
download | python-caldav-60ec379725b3ffedf57f33e869b15a4abf09464d.zip |
logging and assert handling should be configurable through environment option
-rw-r--r-- | .gitignore | 1 | ||||
-rw-r--r-- | caldav/__init__.py | 2 | ||||
-rw-r--r-- | caldav/davclient.py | 28 | ||||
-rw-r--r-- | caldav/lib/error.py | 27 | ||||
-rw-r--r-- | caldav/objects.py | 13 | ||||
-rwxr-xr-x | setup.py | 2 |
6 files changed, 49 insertions, 24 deletions
@@ -11,7 +11,6 @@ bin build docs/build dist -lib include .Python .*.egg-info diff --git a/caldav/__init__.py b/caldav/__init__.py index e2a6582..433fa5e 100644 --- a/caldav/__init__.py +++ b/caldav/__init__.py @@ -1,6 +1,7 @@ #!/usr/bin/env python from .davclient import DAVClient +## TODO: I don't think I like the practice of "import *" here. Should be revisited prior to launching 1.0 at least. from .objects import * # possibly a bug in the tBaxter fork of vobject, this one has to be @@ -12,7 +13,6 @@ import logging # Silence notification of no default logging handler log = logging.getLogger("caldav") - class NullHandler(logging.Handler): def emit(self, record): pass diff --git a/caldav/davclient.py b/caldav/davclient.py index 140d015..aae27da 100644 --- a/caldav/davclient.py +++ b/caldav/davclient.py @@ -45,12 +45,12 @@ class DAVResponse: if content_length == 0: self._raw = '' self.tree = None - logging.debug("No content delivered") + log.debug("No content delivered") else: #self.tree = etree.parse(response.raw, parser=etree.XMLParser(remove_blank_text=True)) self.tree = etree.XML(response.content, parser=etree.XMLParser(remove_blank_text=True)) if log.level <= logging.DEBUG: - logging.debug(etree.tostring(self.tree, pretty_print=True)) + log.debug(etree.tostring(self.tree, pretty_print=True)) elif (self.headers.get('Content-Type', '').startswith('text/calendar') or self.headers.get('Content-Type', '').startswith('text/plain')): ## text/plain is typically for errors, we shouldn't see it on 200/207 responses. @@ -67,7 +67,7 @@ class DAVResponse: pass if hasattr(self, '_raw'): - logging.debug(self._raw) + log.debug(self._raw) # ref https://github.com/python-caldav/caldav/issues/112 stray CRs may cause problems if type(self._raw) == bytes: self._raw = self._raw.replace(b'\r\n', b'\n') @@ -137,12 +137,12 @@ class DAVResponse: status = None href = None propstats = [] - assert(response.tag == dav.Response.tag) + error.assert_(response.tag == dav.Response.tag) for elem in response: if elem.tag == dav.Status.tag: - assert(not status) + error.assert_(not status) status = elem.text - assert(status) + error.assert_(status) self.validate_status(status) elif elem.tag == dav.Href.tag: assert not href @@ -150,8 +150,8 @@ class DAVResponse: elif elem.tag == dav.PropStat.tag: propstats.append(elem) else: - assert(False) - assert(href) + error.assert_(False) + error.assert_(href) return (href, propstats, status) def find_objects_and_props(self, compatibility_mode=False): @@ -171,10 +171,10 @@ class DAVResponse: if r.tag == dav.SyncToken.tag: self.sync_token = r.text continue - assert(r.tag == dav.Response.tag) + error.assert_(r.tag == dav.Response.tag) (href, propstats, status) = self._parse_response(r) - assert not href in self.objects + error.assert_(not href in self.objects) self.objects[href] = {} ## The properties may be delivered either in one @@ -183,9 +183,9 @@ class DAVResponse: for propstat in propstats: cnt = 0 status = propstat.find(dav.Status.tag) - assert(status is not None) + error.assert_(status is not None) if (status is not None): - assert(len(status) == 0) + error.assert_(len(status) == 0) cnt += 1 self.validate_status(status.text) if not compatibility_mode: @@ -198,7 +198,7 @@ class DAVResponse: self.objects[href][theprop.tag] = theprop ## there shouldn't be any more elements except for status and prop - assert(cnt == len(propstat)) + error.assert_(cnt == len(propstat)) return self.objects @@ -227,7 +227,7 @@ class DAVResponse: else: if not values: return None - assert(len(values)==1) + error.assert_(len(values)==1) return values[0] def expand_simple_props(self, props=[], multi_value_props=[], xpath=None): diff --git a/caldav/lib/error.py b/caldav/lib/error.py index 08afe54..2c38434 100644 --- a/caldav/lib/error.py +++ b/caldav/lib/error.py @@ -2,6 +2,33 @@ # -*- encoding: utf-8 -*- from collections import defaultdict +import logging + +try: + import os + ## one of DEBUG_PDB, DEBUG, DEVELOPMENT, PRODUCTION + debugmode = os.environ['PYTHON_CALDAV_DEBUGMODE'] +except: + ## TODO: the default value here should be set to PRODUCTION prior to release + debugmode = 'DEVELOPMENT' + +log = logging.getLogger('caldav') +if debugmode.startswith('DEBUG'): + log.setLevel(logging.DEBUG) +else: + log.setLevel(logging.WARNING) + +def assert_(condition): + try: + assert(condition) + except AssertionError: + if debugmode == 'PRODUCTION': + log.error("Deviation from expectations found. %s" % ERR_FRAGMENT, exc_info=True) + elif debugmode == 'DEBUG_PDB': + log.error("Deviation from expectations found. Dropping into debugger") + import pdb; pdb.set_trace() + else: + raise ERR_FRAGMENT="Please raise an issue at https://github.com/python-caldav/caldav/issues or reach out to t-caldav@tobixen.no, include this error and the traceback and tell what server you are using" diff --git a/caldav/objects.py b/caldav/objects.py index 5cc9bd2..0a8f07b 100644 --- a/caldav/objects.py +++ b/caldav/objects.py @@ -30,15 +30,12 @@ from caldav.elements import dav, cdav, ical from caldav.lib.python_utilities import to_unicode import logging - log = logging.getLogger('caldav') -log.setLevel(logging.ERROR) def errmsg(r): """Utility for formatting a response xml tree to an error string""" return "%s %s\n\n%s" % (r.status, r.reason, r.raw) - class DAVObject(object): """ @@ -223,7 +220,7 @@ class DAVObject(object): properties = self._handle_xml_response(response, props) - assert(properties) + error.assert_(properties) path = unquote(self.url.path) if path.endswith('/'): @@ -234,17 +231,17 @@ class DAVObject(object): if path in properties: rc = properties[path] elif exchange_path in properties: - logging.error("potential path handling problem with ending slashes. Path given: %s, path found: %s. %s" % (path, exchange_path, error.ERR_FRAGMENT)) + log.error("potential path handling problem with ending slashes. Path given: %s, path found: %s. %s" % (path, exchange_path, error.ERR_FRAGMENT)) rc = properties[exchange_path] elif self.url in properties: rc = properties[self.url] elif '/principal/' in properties and path.endswith('/principal/'): - logging.error("Bypassing a known iCloud bug - path expected in response: %s, path found: /principal/" % (path, error.ERR_FRAGMENT)) + log.error("Bypassing a known iCloud bug - path expected in response: %s, path found: /principal/" % (path, error.ERR_FRAGMENT)) ## The strange thing is that we apparently didn't encounter this problem in bc589093a34f0ed0ef489ad5e9cba048750c9837 or 3ee4e42e2fa8f78b71e5ffd1ef322e4007df7a60 - TODO: check this up rc = properties['/principal/'] else: - logging.error("Possibly the server has a path handling problem. Path expected: %s, path found: %s %s" % (path, str(list(properties.keys)), error.ERR_FRAGMENT)) - import pdb; pdb.set_trace() + log.error("Possibly the server has a path handling problem. Path expected: %s, path found: %s %s" % (path, str(list(properties.keys)), error.ERR_FRAGMENT)) + error.assert_(False) return rc @@ -3,7 +3,9 @@ from setuptools import setup, find_packages import sys +## ATTENTION! when doing releases, the default debugmode in lib/error.py should be set to PRODUCTION. version = '0.8.0pre' +## (TODO: any nicer ways than doing this manually? Make a "releases" branch, maybe?) if __name__ == '__main__': ## For python 2.7 and 3.5 we depend on pytz and tzlocal. For 3.6 and up, batteries are included. Same with mock. |