Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/icalendar/cal/component_factory.py: 98%

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

42 statements  

1"""A factory to create components.""" 

2 

3from __future__ import annotations 

4 

5import re 

6from typing import TYPE_CHECKING, Any 

7 

8from icalendar.caselessdict import CaselessDict 

9from icalendar.parser.string import validate_token 

10 

11if TYPE_CHECKING: 

12 from icalendar import Component 

13 

14 

15class ComponentFactory(CaselessDict): 

16 """Registered components from :rfc:`7953` and :rfc:`5545`. 

17 

18 To get a component, use this class as shown below. 

19 

20 .. code-block:: pycon 

21 

22 >>> from icalendar import ComponentFactory 

23 >>> factory = ComponentFactory() 

24 >>> event_class = factory.get_component_class('VEVENT') 

25 >>> event_class() 

26 VEVENT({}) 

27 

28 Automatically creates custom component classes for unknown names (X-components, 

29 IANA-components). Custom components are never dropped per :rfc:`5545`. 

30 

31 .. code-block:: pycon 

32 

33 >>> factory = ComponentFactory() 

34 >>> custom_class = factory.get_component_class('X-VENDOR') 

35 >>> custom_class() 

36 X-VENDOR({}) 

37 

38 If a component class is not yet supported, it can be either created 

39 using :meth:`get_component_class` or added manually as a subclass of 

40 :class:`~icalendar.cal.component.Component`. 

41 See :doc:`/how-to/custom-components` for details. 

42 """ 

43 

44 def __init__(self, *args: Any, **kwargs: Any) -> None: 

45 """Set keys to upper for initial dict.""" 

46 super().__init__(*args, **kwargs) 

47 from icalendar.cal.alarm import Alarm 

48 from icalendar.cal.availability import Availability 

49 from icalendar.cal.available import Available 

50 from icalendar.cal.calendar import Calendar 

51 from icalendar.cal.event import Event 

52 from icalendar.cal.free_busy import FreeBusy 

53 from icalendar.cal.journal import Journal 

54 from icalendar.cal.timezone import ( 

55 Timezone, 

56 TimezoneDaylight, 

57 TimezoneStandard, 

58 ) 

59 from icalendar.cal.todo import Todo 

60 

61 self.add_component_class(Calendar) 

62 self.add_component_class(Event) 

63 self.add_component_class(Todo) 

64 self.add_component_class(Journal) 

65 self.add_component_class(FreeBusy) 

66 self.add_component_class(Timezone) 

67 self.add_component_class(TimezoneStandard) 

68 self.add_component_class(TimezoneDaylight) 

69 self.add_component_class(Alarm) 

70 self.add_component_class(Available) 

71 self.add_component_class(Availability) 

72 

73 def add_component_class(self, cls: type[Component]) -> None: 

74 """Add a component class to the factory. 

75 

76 Parameters: 

77 cls: The component class to add. 

78 """ 

79 self[cls.name] = cls 

80 

81 def get_component_class(self, name: str) -> type[Component]: 

82 """Get the component class from the factory. 

83 

84 This also creates and adds the component class if it does not exist. 

85 

86 Parameters: 

87 name: The name of the component, for example, ``"VCALENDAR"``. 

88 

89 Returns: 

90 The registered component class. 

91 

92 Raises: 

93 ~icalendar.error.InvalidToken: If the name is not a valid iCalendar 

94 token. 

95 """ 

96 component_class = self.get(name) 

97 if component_class is None: 

98 validate_token(name) 

99 from icalendar.cal.component import Component 

100 

101 component_class = type( 

102 re.sub(r"[^\w]+", "", name), (Component,), {"name": name.upper()} 

103 ) 

104 self.add_component_class(component_class) 

105 return component_class 

106 

107 

108__all__ = ["ComponentFactory"]