File: topicutils.py

package info (click to toggle)
wxpython3.0 3.0.2.0%2Bdfsg-4
  • links: PTS, VCS
  • area: main
  • in suites: stretch
  • size: 482,760 kB
  • ctags: 518,293
  • sloc: cpp: 2,127,226; python: 294,045; makefile: 51,942; ansic: 19,033; sh: 3,013; xml: 1,629; perl: 17
file content (118 lines) | stat: -rw-r--r-- 3,842 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
"""
Various utilities used by topic-related modules. 

:copyright: Copyright since 2006 by Oliver Schoenborn, all rights reserved.
:license: BSD, see LICENSE_BSD_Simple.txt for details.

"""

from textwrap import TextWrapper, dedent

from .topicexc import TopicNameError

from .. import py2and3

__all__ = []


UNDERSCORE = '_' # topic name can't start with this
# just want something unlikely to clash with user's topic names
ALL_TOPICS = 'ALL_TOPICS'


class WeakNone:
    """Pretend to be a weak reference to nothing. Used by ArgsInfos to
    refer to parent when None so no if-else blocks needed. """
    def __call__(self):
        return None


def smartDedent(paragraph):
    """Dedent paragraph using textwrap.dedent(), but properly dedents
    even if the first line of paragraph does not contain blanks. 
    This handles the case where a user types a documentation string as 
        '''A long string spanning
        several lines.'''
    """
    if paragraph.startswith(' '):
        para = dedent(paragraph)
    else:
        lines = paragraph.split('\n')
        exceptFirst = dedent('\n'.join(lines[1:]))
        para = lines[0]+exceptFirst
    return para


import re
_validNameRE = re.compile(r'[-0-9a-zA-Z]\w*')


def validateName(topicName):
    """Raise TopicNameError if nameTuple not valid as topic name."""
    topicNameTuple = tupleize(topicName)
    if not topicNameTuple:
        reason = 'name tuple must have at least one item!'
        raise TopicNameError(None, reason)

    class topic: pass
    for subname in topicNameTuple:
        if not subname:
            reason = 'can\'t contain empty string or None'
            raise TopicNameError(topicNameTuple, reason)

        if subname.startswith(UNDERSCORE):
            reason = 'must not start with "%s"' % UNDERSCORE
            raise TopicNameError(topicNameTuple, reason)

        if subname == ALL_TOPICS:
            reason = 'string "%s" is reserved for root topic' % ALL_TOPICS
            raise TopicNameError(topicNameTuple, reason)

        if _validNameRE.match(subname) is None:
            reason = 'element #%s ("%s") has invalid characters' % \
                (1+list(topicNameTuple).index(subname), subname)
            raise TopicNameError(topicNameTuple, reason)


def stringize(topicName):
    """If topicName is a string, just return it
    as is. If it is a topic definition object (ie an object that has 
    'msgDataSpec' as data member), return the dotted name of corresponding
    topic. Otherwise, assume topicName is a tuple and convert it to to a 
    dotted name i.e. ('a','b','c') => 'a.b.c'. Empty name is not allowed 
    (ValueError). The reverse operation is tupleize(topicName)."""
    if py2and3.isstring(topicName):
        return topicName
    
    if hasattr(topicName, "msgDataSpec"): 
        return topicName._topicNameStr

    try:
        name = '.'.join(topicName)
    except Exception:
        exc = py2and3.getexcobj()
        raise TopicNameError(topicName, str(exc))
    
    return name


def tupleize(topicName):
    """If topicName is a tuple of strings, just return it as is. Otherwise,
    convert it to tuple, assuming dotted notation used for topicName. I.e. 
    'a.b.c' => ('a','b','c'). Empty topicName is not allowed (ValueError). 
    The reverse operation is stringize(topicNameTuple)."""
    # assume name is most often str; if more often tuple, 
    # then better use isinstance(name, tuple)
    if hasattr(topicName, "msgDataSpec"): 
        topicName = topicName._topicNameStr
    if py2and3.isstring(topicName): 
        topicTuple = tuple(topicName.split('.'))
    else:
        topicTuple = tuple(topicName) # assume already tuple of strings
        
    if not topicTuple:
        raise TopicNameError(topicTuple, "Topic name can't be empty!")
                
    return topicTuple