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

Wyświetl plik

@ -1,7 +1,6 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from icalendar.compat import iteritems from icalendar.compat import iteritems
from icalendar.parser_tools import to_unicode from icalendar.parser_tools import to_unicode
from icalendar.parser_tools import data_encode
try: try:
from collections import OrderedDict from collections import OrderedDict
@ -41,6 +40,9 @@ class CaselessDict(OrderedDict):
super(CaselessDict, self).__delitem__(key) super(CaselessDict, self).__delitem__(key)
self[key_upper] = value 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): def __getitem__(self, key):
key = to_unicode(key) key = to_unicode(key)
return super(CaselessDict, self).__getitem__(key.upper()) return super(CaselessDict, self).__getitem__(key.upper())
@ -89,7 +91,7 @@ class CaselessDict(OrderedDict):
return type(self)(super(CaselessDict, self).copy()) return type(self)(super(CaselessDict, self).copy())
def __repr__(self): def __repr__(self):
return 'CaselessDict(%s)' % dict(self) return '%s(%s)' % (self.name, dict(self))
def __eq__(self, other): def __eq__(self, other):
return self is other or dict(self.items()) == dict(other.items()) 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): # def decoded(self, name):
# "returns a decoded value, or list of same" # "returns a decoded value, or list of same"
def __repr__(self):
return 'Parameters(%s)' % data_encode(self)
def to_ical(self, sorted=True): def to_ical(self, sorted=True):
result = [] result = []
items = list(self.items()) items = list(self.items())

Wyświetl plik

@ -6,6 +6,7 @@ from icalendar import vCalAddress
from icalendar.tests import unittest from icalendar.tests import unittest
import icalendar import icalendar
import re
class TestPropertyParams(unittest.TestCase): class TestPropertyParams(unittest.TestCase):
@ -205,3 +206,11 @@ END:VCALENDAR"""
self.assertEqual(event['attendee'][0].params.to_ical(), self.assertEqual(event['attendee'][0].params.to_ical(),
b'CN=RembrandXS;PARTSTAT=NEEDS-ACTION;RSVP=TRUE') b'CN=RembrandXS;PARTSTAT=NEEDS-ACTION;RSVP=TRUE')
self.assertEqual(event['attendee'][0].params['cn'], u'RembrandXS') 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 icalendar
import pytz import pytz
import re
class TestCalComponent(unittest.TestCase): class TestCalComponent(unittest.TestCase):
@ -306,6 +307,46 @@ class TestCalComponent(unittest.TestCase):
preserved_str = component.to_ical(sorted=False).splitlines() preserved_str = component.to_ical(sorted=False).splitlines()
assert preserved_str == component_str 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): class TestCal(unittest.TestCase):