progs/gallium/python: New home for python statetracker scripts.
[mesa.git] / progs / gallium / python / retrace / interpreter.py
1 #!/usr/bin/env python
2 ##########################################################################
3 #
4 # Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas.
5 # All Rights Reserved.
6 #
7 # Permission is hereby granted, free of charge, to any person obtaining a
8 # copy of this software and associated documentation files (the
9 # "Software"), to deal in the Software without restriction, including
10 # without limitation the rights to use, copy, modify, merge, publish,
11 # distribute, sub license, and/or sell copies of the Software, and to
12 # permit persons to whom the Software is furnished to do so, subject to
13 # the following conditions:
14 #
15 # The above copyright notice and this permission notice (including the
16 # next paragraph) shall be included in all copies or substantial portions
17 # of the Software.
18 #
19 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20 # OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21 # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
22 # IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
23 # ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
24 # TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
25 # SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26 #
27 ##########################################################################
28
29
30 import sys
31 import struct
32
33 import gallium
34 import model
35 import parse as parser
36
37
38 try:
39 from struct import unpack_from
40 except ImportError:
41 def unpack_from(fmt, buf, offset=0):
42 size = struct.calcsize(fmt)
43 return struct.unpack(fmt, buf[offset:offset + size])
44
45
46 def make_image(surface, x=None, y=None, w=None, h=None):
47 if x is None:
48 x = 0
49 if y is None:
50 y = 0
51 if w is None:
52 w = surface.width - x
53 if h is None:
54 h = surface.height - y
55 data = surface.get_tile_rgba8(x, y, surface.width, surface.height)
56
57 import Image
58 outimage = Image.fromstring('RGBA', (w, h), data, "raw", 'RGBA', 0, 1)
59 return outimage
60
61 def save_image(filename, surface, x=None, y=None, w=None, h=None):
62 outimage = make_image(surface, x, y, w, h)
63 outimage.save(filename, "PNG")
64
65 def show_image(surface, title, x=None, y=None, w=None, h=None):
66 outimage = make_image(surface, x, y, w, h)
67
68 import Tkinter as tk
69 from PIL import Image, ImageTk
70 root = tk.Tk()
71
72 root.title(title)
73
74 image1 = ImageTk.PhotoImage(outimage)
75 w = image1.width()
76 h = image1.height()
77 x = 100
78 y = 100
79 root.geometry("%dx%d+%d+%d" % (w, h, x, y))
80 panel1 = tk.Label(root, image=image1)
81 panel1.pack(side='top', fill='both', expand='yes')
82 panel1.image = image1
83 root.mainloop()
84
85
86 class Struct:
87 """C-like struct"""
88
89 # A basic Python class can pass as a C-like structure
90 pass
91
92
93 struct_factories = {
94 "pipe_blend_color": gallium.BlendColor,
95 "pipe_blend_state": gallium.Blend,
96 #"pipe_clip_state": gallium.Clip,
97 #"pipe_buffer": gallium.Buffer,
98 "pipe_depth_state": gallium.Depth,
99 "pipe_stencil_state": gallium.Stencil,
100 "pipe_alpha_state": gallium.Alpha,
101 "pipe_depth_stencil_alpha_state": gallium.DepthStencilAlpha,
102 #"pipe_framebuffer_state": gallium.Framebuffer,
103 "pipe_poly_stipple": gallium.PolyStipple,
104 "pipe_rasterizer_state": gallium.Rasterizer,
105 "pipe_sampler_state": gallium.Sampler,
106 "pipe_scissor_state": gallium.Scissor,
107 #"pipe_shader_state": gallium.Shader,
108 #"pipe_vertex_buffer": gallium.VertexBuffer,
109 "pipe_vertex_element": gallium.VertexElement,
110 "pipe_viewport_state": gallium.Viewport,
111 #"pipe_texture": gallium.Texture,
112 }
113
114
115 member_array_factories = {
116 #"pipe_rasterizer_state": {"sprite_coord_mode": gallium.ByteArray},
117 "pipe_poly_stipple": {"stipple": gallium.UnsignedArray},
118 "pipe_viewport_state": {"scale": gallium.FloatArray, "translate": gallium.FloatArray},
119 #"pipe_clip_state": {"ucp": gallium.FloatArray},
120 "pipe_depth_stencil_alpha_state": {"stencil": gallium.StencilArray},
121 "pipe_blend_color": {"color": gallium.FloatArray},
122 "pipe_sampler_state": {"border_color": gallium.FloatArray},
123 }
124
125
126 class Translator(model.Visitor):
127 """Translate model arguments into regular Python objects"""
128
129 def __init__(self, interpreter):
130 self.interpreter = interpreter
131 self.result = None
132
133 def visit(self, node):
134 self.result = None
135 node.visit(self)
136 return self.result
137
138 def visit_literal(self, node):
139 self.result = node.value
140
141 def visit_named_constant(self, node):
142 # lookup the named constant in the gallium module
143 self.result = getattr(gallium, node.name)
144
145 def visit_array(self, node):
146 array = []
147 for element in node.elements:
148 array.append(self.visit(element))
149 self.result = array
150
151 def visit_struct(self, node):
152 struct_factory = struct_factories.get(node.name, Struct)
153 struct = struct_factory()
154 for member_name, member_node in node.members:
155 member_value = self.visit(member_node)
156 try:
157 array_factory = member_array_factories[node.name][member_name]
158 except KeyError:
159 pass
160 else:
161 assert isinstance(member_value, list)
162 array = array_factory(len(member_value))
163 for i in range(len(member_value)):
164 array[i] = member_value[i]
165 member_value = array
166 #print node.name, member_name, member_value
167 assert isinstance(struct, Struct) or hasattr(struct, member_name)
168 setattr(struct, member_name, member_value)
169 self.result = struct
170
171 def visit_pointer(self, node):
172 self.result = self.interpreter.lookup_object(node.address)
173
174
175 class Object:
176
177 def __init__(self, interpreter, real):
178 self.interpreter = interpreter
179 self.real = real
180
181
182 class Global(Object):
183
184 def __init__(self, interpreter, real):
185 self.interpreter = interpreter
186 self.real = real
187
188 def pipe_winsys_create(self):
189 return Winsys(self.interpreter, gallium.Device())
190
191 def pipe_screen_create(self, winsys=None):
192 if winsys is None:
193 real = gallium.Device()
194 else:
195 real = winsys.real
196 return Screen(self.interpreter, real)
197
198 def pipe_context_create(self, screen):
199 context = screen.real.context_create()
200 return Context(self.interpreter, context)
201
202
203 class Winsys(Object):
204
205 def __init__(self, interpreter, real):
206 self.interpreter = interpreter
207 self.real = real
208
209 def get_name(self):
210 pass
211
212 def user_buffer_create(self, data, size):
213 # We don't really care to distinguish between user and regular buffers
214 buffer = self.real.buffer_create(size,
215 4,
216 gallium.PIPE_BUFFER_USAGE_CPU_READ |
217 gallium.PIPE_BUFFER_USAGE_CPU_WRITE )
218 assert size == len(data)
219 buffer.write(data)
220 return buffer
221
222 def buffer_create(self, alignment, usage, size):
223 return self.real.buffer_create(size, alignment, usage)
224
225 def buffer_destroy(self, buffer):
226 pass
227
228 def buffer_write(self, buffer, data, size):
229 assert size == len(data)
230 buffer.write(data)
231
232 def fence_finish(self, fence, flags):
233 pass
234
235 def fence_reference(self, dst, src):
236 pass
237
238 def flush_frontbuffer(self, surface):
239 pass
240
241 def surface_alloc(self):
242 return None
243
244 def surface_release(self, surface):
245 pass
246
247
248 class Transfer:
249
250 def __init__(self, surface, x, y, w, h):
251 self.surface = surface
252 self.x = x
253 self.y = y
254 self.w = w
255 self.h = h
256
257
258 class Screen(Object):
259
260 def destroy(self):
261 pass
262
263 def get_name(self):
264 pass
265
266 def get_vendor(self):
267 pass
268
269 def get_param(self, param):
270 pass
271
272 def get_paramf(self, param):
273 pass
274
275 def is_format_supported(self, format, target, tex_usage, geom_flags):
276 return self.real.is_format_supported(format, target, tex_usage, geom_flags)
277
278 def texture_create(self, templat):
279 return self.real.texture_create(
280 format = templat.format,
281 width = templat.width,
282 height = templat.height,
283 depth = templat.depth,
284 last_level = templat.last_level,
285 target = templat.target,
286 tex_usage = templat.tex_usage,
287 )
288
289 def texture_destroy(self, texture):
290 self.interpreter.unregister_object(texture)
291
292 def texture_release(self, surface):
293 pass
294
295 def get_tex_surface(self, texture, face, level, zslice, usage):
296 if texture is None:
297 return None
298 return texture.get_surface(face, level, zslice)
299
300 def tex_surface_destroy(self, surface):
301 self.interpreter.unregister_object(surface)
302
303 def tex_surface_release(self, surface):
304 pass
305
306 def surface_write(self, surface, data, stride, size):
307 if surface is None:
308 return
309 # assert surface.nblocksy * stride == size
310 surface.put_tile_raw(0, 0, surface.width, surface.height, data, stride)
311
312 def get_tex_transfer(self, texture, face, level, zslice, usage, x, y, w, h):
313 if texture is None:
314 return None
315 transfer = Transfer(texture.get_surface(face, level, zslice), x, y, w, h)
316 if transfer and usage & gallium.PIPE_TRANSFER_READ:
317 if self.interpreter.options.all:
318 self.interpreter.present(transfer.surface, 'transf_read', x, y, w, h)
319 return transfer
320
321 def tex_transfer_destroy(self, transfer):
322 self.interpreter.unregister_object(transfer)
323
324 def transfer_write(self, transfer, stride, data, size):
325 if transfer is None:
326 return
327 transfer.surface.put_tile_raw(transfer.x, transfer.y, transfer.w, transfer.h, data, stride)
328 if self.interpreter.options.all:
329 self.interpreter.present(transfer.surface, 'transf_write', transfer.x, transfer.y, transfer.w, transfer.h)
330
331 def user_buffer_create(self, data, size):
332 # We don't really care to distinguish between user and regular buffers
333 buffer = self.real.buffer_create(size,
334 4,
335 gallium.PIPE_BUFFER_USAGE_CPU_READ |
336 gallium.PIPE_BUFFER_USAGE_CPU_WRITE )
337 assert size == len(data)
338 buffer.write(data)
339 return buffer
340
341 def buffer_create(self, alignment, usage, size):
342 return self.real.buffer_create(size, alignment, usage)
343
344 def buffer_destroy(self, buffer):
345 pass
346
347 def buffer_write(self, buffer, data, size, offset=0):
348 assert size == len(data)
349 buffer.write(data)
350
351 def fence_finish(self, fence, flags):
352 pass
353
354 def fence_reference(self, dst, src):
355 pass
356
357 def flush_frontbuffer(self, surface):
358 pass
359
360
361 class Context(Object):
362
363 def __init__(self, interpreter, real):
364 Object.__init__(self, interpreter, real)
365 self.cbufs = []
366 self.zsbuf = None
367 self.vbufs = []
368 self.velems = []
369 self.dirty = False
370
371 def destroy(self):
372 pass
373
374 def create_blend_state(self, state):
375 return state
376
377 def bind_blend_state(self, state):
378 if state is not None:
379 self.real.set_blend(state)
380
381 def delete_blend_state(self, state):
382 pass
383
384 def create_sampler_state(self, state):
385 return state
386
387 def delete_sampler_state(self, state):
388 pass
389
390 def bind_vertex_sampler_states(self, num_states, states):
391 for i in range(num_states):
392 self.real.set_vertex_sampler(i, states[i])
393
394 def bind_fragment_sampler_states(self, num_states, states):
395 for i in range(num_states):
396 self.real.set_fragment_sampler(i, states[i])
397
398 def create_rasterizer_state(self, state):
399 return state
400
401 def bind_rasterizer_state(self, state):
402 if state is not None:
403 self.real.set_rasterizer(state)
404
405 def delete_rasterizer_state(self, state):
406 pass
407
408 def create_depth_stencil_alpha_state(self, state):
409 return state
410
411 def bind_depth_stencil_alpha_state(self, state):
412 if state is not None:
413 self.real.set_depth_stencil_alpha(state)
414
415 def delete_depth_stencil_alpha_state(self, state):
416 pass
417
418 def create_fs_state(self, state):
419 tokens = str(state.tokens)
420 shader = gallium.Shader(tokens)
421 return shader
422
423 create_vs_state = create_fs_state
424
425 def bind_fs_state(self, state):
426 self.real.set_fragment_shader(state)
427
428 def bind_vs_state(self, state):
429 self.real.set_vertex_shader(state)
430
431 def delete_fs_state(self, state):
432 pass
433
434 delete_vs_state = delete_fs_state
435
436 def set_blend_color(self, state):
437 self.real.set_blend_color(state)
438
439 def set_stencil_ref(self, state):
440 self.real.set_stencil_ref(state)
441
442 def set_clip_state(self, state):
443 _state = gallium.Clip()
444 _state.nr = state.nr
445 if state.nr:
446 # FIXME
447 ucp = gallium.FloatArray(gallium.PIPE_MAX_CLIP_PLANES*4)
448 for i in range(len(state.ucp)):
449 for j in range(len(state.ucp[i])):
450 ucp[i*4 + j] = state.ucp[i][j]
451 _state.ucp = ucp
452 self.real.set_clip(_state)
453
454 def dump_constant_buffer(self, buffer):
455 if not self.interpreter.verbosity(2):
456 return
457
458 data = buffer.read()
459 format = '4f'
460 index = 0
461 for offset in range(0, len(data), struct.calcsize(format)):
462 x, y, z, w = unpack_from(format, data, offset)
463 sys.stdout.write('\tCONST[%2u] = {%10.4f, %10.4f, %10.4f, %10.4f}\n' % (index, x, y, z, w))
464 index += 1
465 sys.stdout.flush()
466
467 def set_constant_buffer(self, shader, index, buffer):
468 if buffer is not None:
469 self.real.set_constant_buffer(shader, index, buffer)
470
471 self.dump_constant_buffer(buffer)
472
473 def set_framebuffer_state(self, state):
474 _state = gallium.Framebuffer()
475 _state.width = state.width
476 _state.height = state.height
477 _state.nr_cbufs = state.nr_cbufs
478 for i in range(len(state.cbufs)):
479 _state.set_cbuf(i, state.cbufs[i])
480 _state.set_zsbuf(state.zsbuf)
481 self.real.set_framebuffer(_state)
482
483 self.cbufs = state.cbufs
484 self.zsbuf = state.zsbuf
485
486 def set_polygon_stipple(self, state):
487 self.real.set_polygon_stipple(state)
488
489 def set_scissor_state(self, state):
490 self.real.set_scissor(state)
491
492 def set_viewport_state(self, state):
493 self.real.set_viewport(state)
494
495 def set_fragment_sampler_textures(self, num_textures, textures):
496 for i in range(num_textures):
497 self.real.set_fragment_sampler_texture(i, textures[i])
498
499 def set_vertex_sampler_textures(self, num_textures, textures):
500 for i in range(num_textures):
501 self.real.set_vertex_sampler_texture(i, textures[i])
502
503 def set_vertex_buffers(self, num_buffers, buffers):
504 self.vbufs = buffers[0:num_buffers]
505 for i in range(num_buffers):
506 vbuf = buffers[i]
507 self.real.set_vertex_buffer(
508 i,
509 stride = vbuf.stride,
510 max_index = vbuf.max_index,
511 buffer_offset = vbuf.buffer_offset,
512 buffer = vbuf.buffer,
513 )
514
515 def set_vertex_elements(self, num_elements, elements):
516 self.velems = elements[0:num_elements]
517 for i in range(num_elements):
518 self.real.set_vertex_element(i, elements[i])
519 self.real.set_vertex_elements(num_elements)
520
521 def dump_vertices(self, start, count):
522 if not self.interpreter.verbosity(2):
523 return
524
525 for index in range(start, start + count):
526 if index >= start + 16:
527 sys.stdout.write('\t...\n')
528 break
529 sys.stdout.write('\t{\n')
530 for velem in self.velems:
531 vbuf = self.vbufs[velem.vertex_buffer_index]
532
533 offset = vbuf.buffer_offset + velem.src_offset + vbuf.stride*index
534 format = {
535 gallium.PIPE_FORMAT_R32_FLOAT: 'f',
536 gallium.PIPE_FORMAT_R32G32_FLOAT: '2f',
537 gallium.PIPE_FORMAT_R32G32B32_FLOAT: '3f',
538 gallium.PIPE_FORMAT_R32G32B32A32_FLOAT: '4f',
539 gallium.PIPE_FORMAT_B8G8R8A8_UNORM: '4B',
540 gallium.PIPE_FORMAT_R8G8B8A8_UNORM: '4B',
541 gallium.PIPE_FORMAT_R16G16B16_SNORM: '3h',
542 }[velem.src_format]
543
544 data = vbuf.buffer.read()
545 values = unpack_from(format, data, offset)
546 sys.stdout.write('\t\t{' + ', '.join(map(str, values)) + '},\n')
547 assert len(values) == velem.nr_components
548 sys.stdout.write('\t},\n')
549 sys.stdout.flush()
550
551 def dump_indices(self, ibuf, isize, start, count):
552 if not self.interpreter.verbosity(2):
553 return
554
555 format = {
556 1: 'B',
557 2: 'H',
558 4: 'I',
559 }[isize]
560
561 assert struct.calcsize(format) == isize
562
563 data = ibuf.read()
564 maxindex, minindex = 0, 0xffffffff
565
566 sys.stdout.write('\t{\n')
567 for i in range(start, start + count):
568 if i >= start + 16:
569 sys.stdout.write('\t...\n')
570 break
571 offset = i*isize
572 index, = unpack_from(format, data, offset)
573 sys.stdout.write('\t\t%u,\n' % index)
574 minindex = min(minindex, index)
575 maxindex = max(maxindex, index)
576 sys.stdout.write('\t},\n')
577 sys.stdout.flush()
578
579 return minindex, maxindex
580
581 def draw_arrays(self, mode, start, count):
582 self.dump_vertices(start, count)
583
584 self.real.draw_arrays(mode, start, count)
585 self._set_dirty()
586
587 def draw_elements(self, indexBuffer, indexSize, mode, start, count):
588 if self.interpreter.verbosity(2):
589 minindex, maxindex = self.dump_indices(indexBuffer, indexSize, start, count)
590 self.dump_vertices(minindex, maxindex - minindex)
591
592 self.real.draw_elements(indexBuffer, indexSize, mode, start, count)
593 self._set_dirty()
594
595 def draw_range_elements(self, indexBuffer, indexSize, minIndex, maxIndex, mode, start, count):
596 if self.interpreter.verbosity(2):
597 minindex, maxindex = self.dump_indices(indexBuffer, indexSize, start, count)
598 minindex = min(minindex, minIndex)
599 maxindex = min(maxindex, maxIndex)
600 self.dump_vertices(minindex, maxindex - minindex)
601
602 self.real.draw_range_elements(indexBuffer, indexSize, minIndex, maxIndex, mode, start, count)
603 self._set_dirty()
604
605 def surface_copy(self, dest, destx, desty, src, srcx, srcy, width, height):
606 if dest is not None and src is not None:
607 if self.interpreter.options.all:
608 self.interpreter.present(src, 'surface_copy_src', srcx, srcy, width, height)
609 self.real.surface_copy(dest, destx, desty, src, srcx, srcy, width, height)
610 if dest in self.cbufs:
611 self._set_dirty()
612 flags = gallium.PIPE_FLUSH_FRAME
613 else:
614 flags = 0
615 self.flush(flags)
616 if self.interpreter.options.all:
617 self.interpreter.present(dest, 'surface_copy_dest', destx, desty, width, height)
618
619 def is_texture_referenced(self, texture, face, level):
620 #return self.real.is_texture_referenced(format, texture, face, level)
621 pass
622
623 def is_buffer_referenced(self, buf):
624 #return self.real.is_buffer_referenced(format, buf)
625 pass
626
627 def _set_dirty(self):
628 if self.interpreter.options.step:
629 self._present()
630 else:
631 self.dirty = True
632
633 def flush(self, flags):
634 self.real.flush(flags)
635 if self.dirty:
636 if flags & gallium.PIPE_FLUSH_FRAME:
637 self._present()
638 self.dirty = False
639 return None
640
641 def clear(self, buffers, rgba, depth, stencil):
642 _rgba = gallium.FloatArray(4)
643 for i in range(4):
644 _rgba[i] = rgba[i]
645 self.real.clear(buffers, _rgba, depth, stencil)
646
647 def _present(self):
648 self.real.flush()
649
650 if self.cbufs and self.cbufs[0]:
651 self.interpreter.present(self.cbufs[0], "cbuf")
652 if self.zsbuf:
653 if self.interpreter.options.all:
654 self.interpreter.present(self.zsbuf, "zsbuf")
655
656
657 class Interpreter(parser.TraceDumper):
658
659 ignore_calls = set((
660 ('pipe_screen', 'is_format_supported'),
661 ('pipe_screen', 'get_param'),
662 ('pipe_screen', 'get_paramf'),
663 ))
664
665 def __init__(self, stream, options):
666 parser.TraceDumper.__init__(self, stream)
667 self.options = options
668 self.objects = {}
669 self.result = None
670 self.globl = Global(self, None)
671 self.call_no = None
672
673 def register_object(self, address, object):
674 self.objects[address] = object
675
676 def unregister_object(self, object):
677 # FIXME:
678 pass
679
680 def lookup_object(self, address):
681 return self.objects[address]
682
683 def interpret(self, trace):
684 for call in trace.calls:
685 self.interpret_call(call)
686
687 def handle_call(self, call):
688 if self.options.stop and call.no > self.options.stop:
689 sys.exit(0)
690
691 if (call.klass, call.method) in self.ignore_calls:
692 return
693
694 self.call_no = call.no
695
696 if self.verbosity(1):
697 parser.TraceDumper.handle_call(self, call)
698 sys.stdout.flush()
699
700 args = [(str(name), self.interpret_arg(arg)) for name, arg in call.args]
701
702 if call.klass:
703 name, obj = args[0]
704 args = args[1:]
705 else:
706 obj = self.globl
707
708 method = getattr(obj, call.method)
709 ret = method(**dict(args))
710
711 if call.ret and isinstance(call.ret, model.Pointer):
712 if ret is None:
713 sys.stderr.write('warning: NULL returned\n')
714 self.register_object(call.ret.address, ret)
715
716 self.call_no = None
717
718 def interpret_arg(self, node):
719 translator = Translator(self)
720 return translator.visit(node)
721
722 def verbosity(self, level):
723 return self.options.verbosity >= level
724
725 def present(self, surface, description, x=None, y=None, w=None, h=None):
726 if self.call_no < self.options.start:
727 return
728
729 if self.options.images:
730 filename = '%04u_%s.png' % (self.call_no, description)
731 save_image(filename, surface, x, y, w, h)
732 else:
733 title = '%u. %s' % (self.call_no, description)
734 show_image(surface, title, x, y, w, h)
735
736
737 class Main(parser.Main):
738
739 def get_optparser(self):
740 optparser = parser.Main.get_optparser(self)
741 optparser.add_option("-q", "--quiet", action="store_const", const=0, dest="verbosity", help="no messages")
742 optparser.add_option("-v", "--verbose", action="count", dest="verbosity", default=1, help="increase verbosity level")
743 optparser.add_option("-i", "--images", action="store_true", dest="images", default=False, help="save images instead of showing them")
744 optparser.add_option("-a", "--all", action="store_true", dest="all", default=False, help="show depth, stencil, and transfers")
745 optparser.add_option("-s", "--step", action="store_true", dest="step", default=False, help="step trhough every draw")
746 optparser.add_option("-f", "--from", action="store", type="int", dest="start", default=0, help="from call no")
747 optparser.add_option("-t", "--to", action="store", type="int", dest="stop", default=0, help="until call no")
748 return optparser
749
750 def process_arg(self, stream, options):
751 parser = Interpreter(stream, options)
752 parser.parse()
753
754
755 if __name__ == '__main__':
756 Main().main()