Statistics
| Branch: | Tag: | Revision:

root / grc / base / Platform.py @ f2e366cc

History | View | Annotate | Download (7 kB)

1
"""
2
Copyright 2008, 2009, 2011 Free Software Foundation, Inc.
3
This file is part of GNU Radio
4
5
GNU Radio Companion is free software; you can redistribute it and/or
6
modify it under the terms of the GNU General Public License
7
as published by the Free Software Foundation; either version 2
8
of the License, or (at your option) any later version.
9
10
GNU Radio Companion is distributed in the hope that it will be useful,
11
but WITHOUT ANY WARRANTY; without even the implied warranty of
12
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
GNU General Public License for more details.
14
15
You should have received a copy of the GNU General Public License
16
along with this program; if not, write to the Free Software
17
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
18
"""
19
20
#Perform python integrity checks:
21
# GRC will not work with interpreters that fail the checks below.
22
# This can fail on interpreters built with special optimizations.
23
try:
24
        assert False
25
        raise Exception, 'Failed python integrity check: assert not supported'
26
except AssertionError: pass
27
if __doc__ is None:
28
        raise Exception, 'Failed python integrity check: __doc__ not supported'
29
30
import os
31
import sys
32
from .. base import ParseXML, odict
33
from Element import Element as _Element
34
from FlowGraph import FlowGraph as _FlowGraph
35
from Connection import Connection as _Connection
36
from Block import Block as _Block
37
from Port import Port as _Port
38
from Param import Param as _Param
39
from Constants import BLOCK_TREE_DTD, FLOW_GRAPH_DTD
40
41
class Platform(_Element):
42
43
        def __init__(self, name, version, key,
44
                block_paths, block_dtd, default_flow_graph, generator,
45
                license='', website=None, colors=[]):
46
                """
47
                Make a platform from the arguments.
48
                @param name the platform name
49
                @param version the version string
50
                @param key the unique platform key
51
                @param block_paths the file paths to blocks in this platform
52
                @param block_dtd the dtd validator for xml block wrappers
53
                @param default_flow_graph the default flow graph file path
54
                @param generator the generator class for this platform
55
                @param colors a list of title, color_spec tuples
56
                @param license a multi-line license (first line is copyright)
57
                @param website the website url for this platform
58
                @return a platform object
59
                """
60
                _Element.__init__(self)
61
                self._name = name
62
                self._version = version
63
                self._key = key
64
                self._license = license
65
                self._website = website
66
                self._block_paths = block_paths
67
                self._block_dtd = block_dtd
68
                self._default_flow_graph = default_flow_graph
69
                self._generator = generator
70
                self._colors = colors
71
                #create a dummy flow graph for the blocks
72
                self._flow_graph = _Element(self)
73
                #search for *.xml files in the given search path
74
                xml_files = list()
75
                for block_path in self._block_paths:
76
                        if os.path.isfile(block_path): xml_files.append(block_path)
77
                        elif os.path.isdir(block_path):
78
                                for dirpath, dirnames, filenames in os.walk(block_path):
79
                                        for filename in sorted(filter(lambda f: f.endswith('.xml'), filenames)):
80
                                                xml_files.append(os.path.join(dirpath, filename))
81
                #load the blocks
82
                self._blocks = odict()
83
                self._blocks_n = odict()
84
                self._block_tree_files = list()
85
                for xml_file in xml_files:
86
                        try: #try to add the xml file as a block wrapper
87
                                ParseXML.validate_dtd(xml_file, self._block_dtd)
88
                                n = ParseXML.from_file(xml_file).find('block')
89
                                #inject block wrapper path
90
                                n['block_wrapper_path'] = xml_file
91
                                block = self.Block(self._flow_graph, n)
92
                                key = block.get_key()
93
                                #test against repeated keys
94
                                try:
95
                                        assert key not in self.get_block_keys()
96
                                        #store the block
97
                                        self._blocks[key] = block
98
                                        self._blocks_n[key] = n
99
                                except AssertionError:
100
                                        print >> sys.stderr, 'Warning: Block with key "%s" already exists.\n\tIgnoring: %s'%(key, xml_file)
101
                        except ParseXML.XMLSyntaxError, e: 
102
                                try: #try to add the xml file as a block tree
103
                                        ParseXML.validate_dtd(xml_file, BLOCK_TREE_DTD)
104
                                        self._block_tree_files.append(xml_file)
105
                                except ParseXML.XMLSyntaxError, e:
106
                                        print >> sys.stderr, 'Warning: Block validation failed:\n\t%s\n\tIgnoring: %s'%(e, xml_file)
107
                        except Exception, e:
108
                                print >> sys.stderr, 'Warning: Block loading failed:\n\t%s\n\tIgnoring: %s'%(e, xml_file)
109
110
        def parse_flow_graph(self, flow_graph_file):
111
                """
112
                Parse a saved flow graph file.
113
                Ensure that the file exists, and passes the dtd check.
114
                @param flow_graph_file the flow graph file
115
                @return nested data
116
                @throws exception if the validation fails
117
                """
118
                flow_graph_file = flow_graph_file or self._default_flow_graph
119
                open(flow_graph_file, 'r') #test open
120
                ParseXML.validate_dtd(flow_graph_file, FLOW_GRAPH_DTD)
121
                return ParseXML.from_file(flow_graph_file)
122
123
        def load_block_tree(self, block_tree):
124
                """
125
                Load a block tree with categories and blocks.
126
                Step 1: Load all blocks from the xml specification.
127
                Step 2: Load blocks with builtin category specifications.
128
                @param block_tree the block tree object
129
                """
130
                #recursive function to load categories and blocks
131
                def load_category(cat_n, parent=[]):
132
                        #add this category
133
                        parent = parent + [cat_n.find('name')]
134
                        block_tree.add_block(parent)
135
                        #recursive call to load sub categories
136
                        map(lambda c: load_category(c, parent), cat_n.findall('cat'))
137
                        #add blocks in this category
138
                        for block_key in cat_n.findall('block'):
139
                                if block_key not in self.get_block_keys():
140
                                        print >> sys.stderr, 'Warning: Block key "%s" not found when loading category tree.'%(block_key)
141
                                        continue
142
                                block = self.get_block(block_key)
143
                                #if it exists, the block's category overrides the block tree
144
                                if not block.get_category(): block_tree.add_block(parent, block)
145
                #load the block tree
146
                for block_tree_file in self._block_tree_files:
147
                        #recursivly add all blocks in the tree
148
                        load_category(ParseXML.from_file(block_tree_file).find('cat'))
149
                #add all other blocks, use the catgory tag
150
                for block in self.get_blocks():
151
                        #blocks with empty categories are in the xml block tree or hidden
152
                        if not block.get_category(): continue
153
                        block_tree.add_block(block.get_category(), block)
154
155
        def __str__(self): return 'Platform - %s(%s)'%(self.get_key(), self.get_name())
156
157
        def is_platform(self): return True
158
159
        def get_new_flow_graph(self): return self.FlowGraph(platform=self)
160
161
        def get_generator(self): return self._generator
162
163
        ##############################################
164
        # Access Blocks
165
        ##############################################
166
        def get_block_keys(self): return self._blocks.keys()
167
        def get_block(self, key): return self._blocks[key]
168
        def get_blocks(self): return self._blocks.values()
169
        def get_new_block(self, flow_graph, key): return self.Block(flow_graph, n=self._blocks_n[key])
170
171
        def get_name(self): return self._name
172
        def get_version(self): return self._version
173
        def get_key(self): return self._key
174
        def get_license(self): return self._license
175
        def get_website(self): return self._website
176
        def get_colors(self): return self._colors
177
178
        ##############################################
179
        # Constructors
180
        ##############################################
181
        FlowGraph = _FlowGraph
182
        Connection = _Connection
183
        Block = _Block
184
        Port = _Port
185
        Param = _Param