Allow including source filename in auto-generated header.
[asn2quickder] / asn1ate / support / pygen.py
1 # Copyright (c) 2013, Schneider Electric Buildings AB
2 # All rights reserved.
3 #
4 # Redistribution and use in source and binary forms, with or without
5 # modification, are permitted provided that the following conditions are met:
6 #     * Redistributions of source code must retain the above copyright
7 #       notice, this list of conditions and the following disclaimer.
8 #     * Redistributions in binary form must reproduce the above copyright
9 #       notice, this list of conditions and the following disclaimer in the
10 #       documentation and/or other materials provided with the distribution.
11 #     * Neither the name of Schneider Electric Buildings AB nor the
12 #       names of contributors may be used to endorse or promote products
13 #       derived from this software without specific prior written permission.
14 #
15 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
16 # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17 # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18 # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
19 # ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
20 # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
21 # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
22 # ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
24 # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25
26 try:
27     # Python 2
28     from cStringIO import StringIO
29 except ImportError:
30     # Python 3
31     from io import StringIO
32
33 from datetime import datetime
34
35
36 def auto_generated_header(source_filename=None):
37     prefix = '# Auto-generated'
38     if source_filename:
39         prefix += ' from %s' % source_filename
40
41     return '%s by asn1ate on %s' % (prefix, datetime.now())
42
43
44 class NullBackend(object):
45     """ Code generator to create an empty file.
46     Used to create __init__.py files.
47     """
48     def __init__(self, *args):
49         pass
50
51     def generate_code(self, *args):
52         pass
53
54
55 class PythonWriter(object):
56     """ Indentation-aware text stream. """
57     def __init__(self, out_stream, indent_size=4):
58         self.out = out_stream
59         self.indent_size = indent_size
60         self.current_indent = 0
61
62     def push_indent(self):
63         self.current_indent += self.indent_size
64
65     def pop_indent(self):
66         self.current_indent -= self.indent_size
67
68     def write_line(self, line):
69         if line is not None:
70             line = self._indent(line) if line else line
71             self.out.write('%s\n' % line)
72
73     def write_blanks(self, count=1):
74         for i in range(0, count):
75             self.out.write('\n')
76
77     def write_block(self, block):
78         """ Reindents after every line break. """
79         block = block.rstrip()
80         for line in block.split('\n'):
81             self.write_line(line)
82
83     def write_enumeration(self, items):
84         self.write_block(',\n'.join(items))
85
86     def get_fragment(self):
87         return PythonFragment(self.indent_size)
88
89     def _indent(self, line):
90         return ' ' * self.current_indent + line
91
92
93 class PythonFragment(PythonWriter):
94     """ A buffering python writer, useful for nested structures.
95     """
96     def __init__(self, indent_size=4):
97         self.buf = StringIO()
98         super(PythonFragment, self).__init__(self.buf, indent_size)
99
100     def __str__(self):
101         return self.buf.getvalue()