I don't even
[librarian.git] / librarian / utils.py
1 # -*- coding: utf-8 -*-
2 #
3 # This file is part of Librarian, licensed under GNU Affero GPLv3 or later.
4 # Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
5 #
6 import os
7
8
9 class Context(object):
10     """ Processing context.
11     
12     >>> ctx = Context(a=1)
13     >>> subctx = Context(ctx, a=2)
14     >>> ctx.b = 3
15     >>> print subctx.a, subctx.b
16     2 3
17
18     """
19     def __init__(self, _upctx=None, **initial):
20         object.__setattr__(self, '_upctx', _upctx)
21         object.__setattr__(self, '_data', initial or {})
22
23     def __getattr__(self, name):
24         if name in self._data:
25             return self._data[name]
26         elif self._upctx is not None:
27             return getattr(self._upctx, name)
28         else:
29             raise AttributeError("'%s' object has no attribute '%s'" % (type(self), name))
30
31     def __setattr__(self, name, value):
32         try:
33             self.try_setattr(name, value)
34         except ValueError:
35             self._data[name] = value
36
37     def try_setattr(self, name, value):
38         if name in self._data:
39             self._data[name] = value
40         elif self._upctx is not None:
41             self._upctx.try_setattr(name, value)
42         else:
43             raise ValueError
44
45
46 class XMLNamespace(object):
47     """A handy structure to repsent names in an XML namespace."""
48     def __init__(self, uri):
49         self.uri = uri
50
51     def __call__(self, tag):
52         return '{%s}%s' % (self.uri, tag)
53
54     def __contains__(self, tag):
55         return tag.startswith('{' + str(self) + '}')
56
57     def __repr__(self):
58         return 'XMLNamespace(%r)' % self.uri
59
60     def __str__(self):
61         return '%s' % self.uri
62
63
64 def extend_element(container, element=None, text=None):
65     """ Extends XML element with another one's contents.
66
67     Differs from etree.Element.extend by taking the text into account.
68
69     >>> from lxml import etree
70     >>> container = etree.fromstring("<A><B/></A>")
71     >>> element = etree.fromstring("<_>a<b/>c</_>")
72     >>> extend_element(container, element)
73     >>> print etree.tostring(container)
74     <A><B/>a<b/>c</A>
75
76     """
77     add_text = (text or "") + (element.text or "" if element is not None else "")
78     if add_text:
79         if len(container):
80             container[-1].tail = (container[-1].tail or "") + add_text
81         else:
82             container.text = (container.text or "") + add_text
83     if element is not None:
84         container.extend(element)
85
86
87 def get_resource(path):
88     return os.path.join(os.path.dirname(__file__), path)