File size: 2,486 Bytes
64772a4
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
from __future__ import absolute_import

import os
import sys
import errno

try:
    from lxml import etree
    have_lxml = True
except ImportError:
    have_lxml = False
    try:
        from xml.etree import cElementTree as etree
    except ImportError:
        try:
            from xml.etree import ElementTree as etree
        except ImportError:
            etree = None

from ..Compiler import Errors
from ..Compiler.StringEncoding import EncodedString


def is_valid_tag(name):
    """
    Names like '.0' are used internally for arguments
    to functions creating generator expressions,
    however they are not identifiers.

    See https://github.com/cython/cython/issues/5552
    """
    if isinstance(name, EncodedString):
        if name.startswith(".") and name[1:].isdecimal():
            return False
    return True


class CythonDebugWriter(object):
    """
    Class to output debugging information for cygdb

    It writes debug information to cython_debug/cython_debug_info_<modulename>
    in the build directory.
    """

    def __init__(self, output_dir):
        if etree is None:
            raise Errors.NoElementTreeInstalledException()

        self.output_dir = os.path.join(output_dir or os.curdir, 'cython_debug')
        self.tb = etree.TreeBuilder()
        # set by Cython.Compiler.ParseTreeTransforms.DebugTransform
        self.module_name = None
        self.start('cython_debug', attrs=dict(version='1.0'))

    def start(self, name, attrs=None):
        if is_valid_tag(name):
            self.tb.start(name, attrs or {})

    def end(self, name):
        if is_valid_tag(name):
            self.tb.end(name)

    def add_entry(self, name, **attrs):
        if is_valid_tag(name):
            self.tb.start(name, attrs)
            self.tb.end(name)

    def serialize(self):
        self.tb.end('Module')
        self.tb.end('cython_debug')
        xml_root_element = self.tb.close()

        try:
            os.makedirs(self.output_dir)
        except OSError as e:
            if e.errno != errno.EEXIST:
                raise

        et = etree.ElementTree(xml_root_element)
        kw = {}
        if have_lxml:
            kw['pretty_print'] = True

        fn = "cython_debug_info_" + self.module_name
        et.write(os.path.join(self.output_dir, fn), encoding="UTF-8", **kw)

        interpreter_path = os.path.join(self.output_dir, 'interpreter')
        with open(interpreter_path, 'w') as f:
            f.write(sys.executable)