1# -*- coding: utf-8 -*-
2
3# Copyright (c) 2005 - 2021 Detlev Offenbach <detlev@die-offenbachs.de>
4#
5
6"""
7Package implementing class browsers for various languages.
8
9Currently it offers class browser support for the following
10programming languages.
11
12<ul>
13<li>CORBA IDL</li>
14<li>JavaScript</li>
15<li>ProtoBuf</li>
16<li>Python 3</li>
17<li>Ruby</li>
18</ul>
19"""
20
21import os
22import importlib
23
24import Preferences
25
26PY_SOURCE = 1
27PTL_SOURCE = 128
28RB_SOURCE = 129
29IDL_SOURCE = 130
30JS_SOURCE = 131
31PROTO_SOURCE = 132
32
33SUPPORTED_TYPES = [PY_SOURCE, PTL_SOURCE, RB_SOURCE, IDL_SOURCE, JS_SOURCE,
34                   PROTO_SOURCE]
35
36__extensions = {
37    "IDL": [".idl"],
38    "Python": [".py", ".pyw", ".ptl"],  # currently not used
39    "Ruby": [".rb"],
40    "JavaScript": [".js"],
41    "ProtoBuf": [".proto"],
42}
43
44
45def readmodule(module, path=None, isPyFile=False):
46    """
47    Read a source file and return a dictionary of classes, functions, modules,
48    etc. .
49
50    The real work of parsing the source file is delegated to the individual
51    file parsers.
52
53    @param module name of the source file
54    @type str
55    @param path list of paths the file should be searched in
56    @type list of str
57    @param isPyFile flag indicating a Python file
58    @type bool
59    @return the resulting dictionary
60    @rtype dict
61    """
62    ext = os.path.splitext(module)[1].lower()
63    path = [] if path is None else path[:]
64
65    if ext in __extensions["IDL"]:
66        from . import idlclbr
67        dictionary = idlclbr.readmodule_ex(module, path)
68        idlclbr._modules.clear()
69    elif ext in __extensions["ProtoBuf"]:
70        from . import protoclbr
71        dictionary = protoclbr.readmodule_ex(module, path)
72        protoclbr._modules.clear()
73    elif ext in __extensions["Ruby"]:
74        from . import rbclbr
75        dictionary = rbclbr.readmodule_ex(module, path)
76        rbclbr._modules.clear()
77    elif ext in __extensions["JavaScript"]:
78        from . import jsclbr
79        dictionary = jsclbr.readmodule_ex(module, path)
80        jsclbr._modules.clear()
81    elif (
82        ext in Preferences.getPython("Python3Extensions") or
83        isPyFile
84    ):
85        from . import pyclbr
86        dictionary = pyclbr.readmodule_ex(module, path, isPyFile=isPyFile)
87        pyclbr._modules.clear()
88    else:
89        # try Python if it is without extension
90        from . import pyclbr
91        dictionary = pyclbr.readmodule_ex(module, path)
92        pyclbr._modules.clear()
93
94    return dictionary
95
96
97def find_module(name, path, isPyFile=False):
98    """
99    Module function to extend the Python module finding mechanism.
100
101    This function searches for files in the given list of paths. If the
102    file name doesn't have an extension or an extension of .py, the normal
103    Python search implemented in the imp module is used. For all other
104    supported files only the paths list is searched.
105
106    @param name file name or module name to search for
107    @type str
108    @param path search paths
109    @type list of str
110    @param isPyFile flag indicating a Python file
111    @type bool
112    @return tuple of the open file, pathname and description. Description
113        is a tuple of file suffix, file mode and file type)
114    @rtype tuple
115    @exception ImportError The file or module wasn't found.
116    """
117    ext = os.path.splitext(name)[1].lower()
118
119    if ext in __extensions["Ruby"]:
120        for p in path:      # only search in path
121            pathname = os.path.join(p, name)
122            if os.path.exists(pathname):
123                return (open(pathname), pathname, (ext, 'r', RB_SOURCE))
124                # __IGNORE_WARNING_Y115__
125        raise ImportError
126
127    elif ext in __extensions["IDL"]:
128        for p in path:      # only search in path
129            pathname = os.path.join(p, name)
130            if os.path.exists(pathname):
131                return (open(pathname), pathname, (ext, 'r', IDL_SOURCE))
132                # __IGNORE_WARNING_Y115__
133        raise ImportError
134
135    elif ext in __extensions["ProtoBuf"]:
136        for p in path:      # only search in path
137            pathname = os.path.join(p, name)
138            if os.path.exists(pathname):
139                return (open(pathname), pathname, (ext, 'r', PROTO_SOURCE))
140                # __IGNORE_WARNING_Y115__
141        raise ImportError
142
143    elif ext in __extensions["JavaScript"]:
144        for p in path:      # only search in path
145            pathname = os.path.join(p, name)
146            if os.path.exists(pathname):
147                return (open(pathname), pathname, (ext, 'r', JS_SOURCE))
148                # __IGNORE_WARNING_Y115__
149        raise ImportError
150
151    elif ext == '.ptl':
152        for p in path:      # only search in path
153            pathname = os.path.join(p, name)
154            if os.path.exists(pathname):
155                return (open(pathname), pathname, (ext, 'r', PTL_SOURCE))
156                # __IGNORE_WARNING_Y115__
157        raise ImportError
158
159    elif (
160        name.lower().endswith(
161            tuple(Preferences.getPython("Python3Extensions"))) or
162        isPyFile
163    ):
164        for p in path:      # search in path
165            pathname = os.path.join(p, name)
166            if os.path.exists(pathname):
167                return (open(pathname), pathname, (ext, 'r', PY_SOURCE))
168                # __IGNORE_WARNING_Y115__
169    raise ImportError
170
171    # standard Python module file
172    if name.lower().endswith('.py'):
173        name = name[:-3]
174
175    spec = importlib.machinery.PathFinder.find_spec(name, path)
176    if spec is None:
177        raise ImportError
178    if isinstance(spec.loader, importlib.machinery.SourceFileLoader):
179        ext = os.path.splitext(spec.origin)[-1]
180        return (open(spec.origin), spec.origin, (ext, 'r', PY_SOURCE))
181        # __IGNORE_WARNING_Y115__
182
183    raise ImportError
184