Change class representation for CaselessDict objects to always include the class name or the class' name attribute, if available. Also show subcomponents for Component objects.

pull/146/head
Johannes Raggam 2014-07-14 13:45:19 +02:00
rodzic ba0b2e58a1
commit fb34cc3998
6 zmienionych plików z 78 dodań i 18 usunięć

Wyświetl plik

@ -4,7 +4,12 @@ Changelog
3.8 (unreleased)
----------------
- Change class representation for CaselessDict objects to always include the
class name or the class' name attribute, if available. Also show
subcomponents for Component objects.
[thet]
- Don't use data_encode for CaselessDict class representation but use dict's
__repr__ method.
[t-8ch]

Wyświetl plik

@ -12,7 +12,6 @@ from icalendar.parser import Parameters
from icalendar.parser import q_join
from icalendar.parser import q_split
from icalendar.parser_tools import DEFAULT_ENCODING
from icalendar.parser_tools import data_encode
from icalendar.prop import TypesFactory
from icalendar.prop import vText, vDDDLists
@ -59,13 +58,13 @@ class Component(CaselessDict):
directy, but rather one of the subclasses.
"""
name = '' # must be defined in each component
required = () # These properties are required
singletons = () # These properties must only appear once
multiple = () # may occur more than once
exclusive = () # These properties are mutually exclusive
inclusive = () # if any occurs the other(s) MUST occur
# ('duration', 'repeat')
name = None # should be defined in each component
required = () # These properties are required
singletons = () # These properties must only appear once
multiple = () # may occur more than once
exclusive = () # These properties are mutually exclusive
inclusive = () # if any occurs the other(s) MUST occur
# ('duration', 'repeat')
ignore_exceptions = False # if True, and we cannot parse this
# component, we will silently ignore
# it, rather than let the exception
@ -262,7 +261,7 @@ class Component(CaselessDict):
"""Recursively traverses component and subcomponents. Returns sequence
of same. If name is passed, only components with name will be returned.
"""
if not name is None:
if name is not None:
name = name.upper()
return self._walk(name)
@ -368,9 +367,6 @@ class Component(CaselessDict):
'{st!r}'.format(**locals()))
return comps[0]
def __repr__(self):
return '%s(%s)' % (self.name, data_encode(self))
def content_line(self, name, value, sorted=True):
"""Returns property as content line.
"""
@ -396,6 +392,16 @@ class Component(CaselessDict):
content_lines = self.content_lines(sorted=sorted)
return content_lines.to_ical()
def __repr__(self):
"""String representation of class with all of it's subcomponents.
"""
subs = ', '.join([str(it) for it in self.subcomponents])
return '%s(%s%s)' % (
self.name,
dict(self),
', %s' % subs if subs else ''
)
#######################################
# components defined in RFC 2445

Wyświetl plik

@ -1,7 +1,6 @@
# -*- coding: utf-8 -*-
from icalendar.compat import iteritems
from icalendar.parser_tools import to_unicode
from icalendar.parser_tools import data_encode
try:
from collections import OrderedDict
@ -41,6 +40,9 @@ class CaselessDict(OrderedDict):
super(CaselessDict, self).__delitem__(key)
self[key_upper] = value
# If name not set, use class name instead
self.name = getattr(self, 'name', None) or type(self).__name__
def __getitem__(self, key):
key = to_unicode(key)
return super(CaselessDict, self).__getitem__(key.upper())
@ -89,7 +91,7 @@ class CaselessDict(OrderedDict):
return type(self)(super(CaselessDict, self).copy())
def __repr__(self):
return 'CaselessDict(%s)' % dict(self)
return '%s(%s)' % (self.name, dict(self))
def __eq__(self, other):
return self is other or dict(self.items()) == dict(other.items())

Wyświetl plik

@ -191,9 +191,6 @@ class Parameters(CaselessDict):
# def decoded(self, name):
# "returns a decoded value, or list of same"
def __repr__(self):
return 'Parameters(%s)' % data_encode(self)
def to_ical(self, sorted=True):
result = []
items = list(self.items())

Wyświetl plik

@ -6,6 +6,7 @@ from icalendar import vCalAddress
from icalendar.tests import unittest
import icalendar
import re
class TestPropertyParams(unittest.TestCase):
@ -205,3 +206,11 @@ END:VCALENDAR"""
self.assertEqual(event['attendee'][0].params.to_ical(),
b'CN=RembrandXS;PARTSTAT=NEEDS-ACTION;RSVP=TRUE')
self.assertEqual(event['attendee'][0].params['cn'], u'RembrandXS')
def test_repr(self):
"""Test correct class representation.
"""
it = Parameters(parameter1='Value1')
self.assertTrue(
re.match("Parameters\({u?'PARAMETER1': 'Value1'}\)", str(it))
)

Wyświetl plik

@ -4,6 +4,7 @@ from icalendar.tests import unittest
import icalendar
import pytz
import re
class TestCalComponent(unittest.TestCase):
@ -306,6 +307,46 @@ class TestCalComponent(unittest.TestCase):
preserved_str = component.to_ical(sorted=False).splitlines()
assert preserved_str == component_str
def test_repr(self):
"""Test correct class representation.
"""
from icalendar.cal import Component, Calendar, Event
component = Component()
component['key1'] = 'value1'
self.assertTrue(
re.match("Component\({u?'KEY1': 'value1'}\)", str(component))
)
calendar = Calendar()
calendar['key1'] = 'value1'
self.assertTrue(
re.match("VCALENDAR\({u?'KEY1': 'value1'}\)", str(calendar))
)
event = Event()
event['key1'] = 'value1'
self.assertTrue(
re.match("VEVENT\({u?'KEY1': 'value1'}\)", str(event))
)
# Representation of nested Components
calendar.add_component(event)
nested = Component(key1='VALUE1', key2='VALUE2')
nested.add_component(component)
nested.add_component(calendar)
nested.add_component(event)
self.assertTrue(
re.match(
"Component\({u?'KEY2': 'VALUE2', u?'KEY1': 'VALUE1'}, Component\({u?'KEY1': 'value1'}\), VCALENDAR\({u?'KEY1': 'value1'}, VEVENT\({u?'KEY1': 'value1'}\)\), VEVENT\({u?'KEY1': 'value1'}\)\)", # nopep8
str(nested)
)
)
class TestCal(unittest.TestCase):