File: module.py

package info (click to toggle)
pypy3 7.3.19%2Bdfsg-2
  • links: PTS, VCS
  • area: main
  • in suites: trixie
  • size: 212,236 kB
  • sloc: python: 2,098,316; ansic: 540,565; sh: 21,462; asm: 14,419; cpp: 4,451; makefile: 4,209; objc: 761; xml: 530; exp: 499; javascript: 314; pascal: 244; lisp: 45; csh: 12; awk: 4
file content (221 lines) | stat: -rw-r--r-- 8,825 bytes parent folder | download | duplicates (2)
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
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
"""
Module objects.
"""

from pypy.interpreter.baseobjspace import W_Root
from pypy.interpreter.error import OperationError, oefmt
from rpython.rlib.objectmodel import we_are_translated, not_rpython


class Module(W_Root):
    """A module."""

    _immutable_fields_ = ["w_dict", "w_userclass?"]

    _frozen = False
    w_userclass = None

    def __init__(self, space, w_name, w_dict=None):
        self.space = space
        if w_dict is None:
            w_dict = space.newdict(module=True)
        self.w_dict = w_dict
        self.w_name = w_name
        if w_name is not None:
            space.setitem(w_dict, space.new_interned_str('__name__'), w_name)
        self.startup_called = False

    def _cleanup_(self):
        """Called by the annotator on prebuilt Module instances.
        We don't have many such modules, but for the ones that
        show up, remove their __file__ rather than translate it
        statically inside the executable."""
        try:
            space = self.space
            space.delitem(self.w_dict, space.newtext('__file__'))
        except OperationError:
            pass

    @not_rpython
    def install(self):
        """installs this module into space.builtin_modules"""
        modulename = self.space.text0_w(self.w_name)
        if modulename in self.space.builtin_modules:
            raise ValueError(
                "duplicate interp-level module enabled for the "
                "app-level module %r" % (modulename,))
        self.space.builtin_modules[modulename] = self

    @not_rpython
    def setup_after_space_initialization(self):
        """to allow built-in modules to do some more setup
        after the space is fully initialized."""

    def init(self, space):
        """This is called each time the module is imported or reloaded
        """
        if not self.startup_called:
            if not we_are_translated():
                # this special case is to handle the case, during annotation,
                # of module A that gets frozen, then module B (e.g. during
                # a getdict()) runs some code that imports A
                if self._frozen:
                    return
            self.startup_called = True
            self.startup(space)

    def startup(self, space):
        """This is called at runtime on import to allow the module to
        do initialization when it is imported for the first time.
        """

    def shutdown(self, space):
        """This is called when the space is shut down, just after
        atexit functions, if the module has been imported.
        """

    def getdict(self, space):
        return self.w_dict

    def descr_module__new__(space, w_subtype, __args__):
        module = space.allocate_instance(Module, w_subtype)
        Module.__init__(module, space, None)
        return module

    def descr_module__init__(self, w_name, w_doc=None):
        space = self.space
        self.w_name = w_name
        if w_doc is None:
            w_doc = space.w_None
        w_dict = self.w_dict
        space.setitem(w_dict, space.new_interned_str('__name__'), w_name)
        space.setitem(w_dict, space.new_interned_str('__doc__'), w_doc)
        init_extra_module_attrs(space, self)

    def descr__reduce__(self, space):
        w_name = space.finditem(self.w_dict, space.newtext('__name__'))
        if (w_name is None or
            not space.isinstance_w(w_name, space.w_text)):
            # maybe raise exception here (XXX this path is untested)
            return space.w_None
        w_modules = space.sys.get('modules')
        if space.finditem(w_modules, w_name) is None:
            #not imported case
            from pypy.interpreter.mixedmodule import MixedModule
            w_mod    = space.getbuiltinmodule('_pickle_support')
            mod      = space.interp_w(MixedModule, w_mod)
            new_inst = mod.get('module_new')
            return space.newtuple2(new_inst,
                                   space.newtuple2(w_name,
                                                   self.getdict(space)),
                                  )
        #already imported case
        w_import = space.builtin.get('__import__')
        tup_return = [
            w_import,
            space.newtuple([
                w_name,
                space.w_None,
                space.w_None,
                space.newtuple([space.newtext('')])
            ])
        ]

        return space.newtuple(tup_return)

    def descr_module__repr__(self, space):
        w_importlib = space.getbuiltinmodule('_frozen_importlib')
        return space.call_method(w_importlib, "_module_repr", self)

    def descr_getattribute(self, space, w_attr):
        from pypy.objspace.descroperation import object_getattribute
        from pypy.module.imp.importing import (is_spec_initializing,
                                 is_spec_uninitialized_submodule)
        try:
            return space.call_function(object_getattribute(space), self, w_attr)
        except OperationError as e:
            if not e.match(space, space.w_AttributeError):
                raise
            w_dict = self.w_dict
            w_getattr = space.finditem(w_dict, space.newtext('__getattr__'))
            if w_getattr is not None:
                return space.call_function(w_getattr, w_attr)
            w_name = space.finditem(self.w_dict, space.newtext('__name__'))
            w_spec = space.finditem(self.w_dict, space.newtext('__spec__'))
            if w_name is None:
                raise oefmt(space.w_AttributeError,
                    "module has no attribute %R", w_attr)
            elif w_spec is not None and is_spec_initializing(space, w_spec):
                raise oefmt(space.w_AttributeError,
                    "partially initialized "
                    "module %R has no attribute %R "
                    "(most likely due to a circular import)",
                    w_name, w_attr
                )
            elif w_spec is not None and is_spec_uninitialized_submodule(space, w_spec, w_attr):
                raise oefmt(space.w_AttributeError,
                    "cannot access submodule %R of module %R "
                    "(most likely due to a circular import)",
                    w_attr, w_name)
            else:
                raise oefmt(space.w_AttributeError,
                    "module %R has no attribute %R", w_name, w_attr)

    def descr_module__dir__(self, space):
        w_dict = space.getattr(self, space.newtext('__dict__'))
        if not space.isinstance_w(w_dict, space.w_dict):
            raise oefmt(space.w_TypeError, "%N.__dict__ is not a dictionary",
                        self)
        w_dir = space.finditem(w_dict, space.newtext('__dir__'))
        if w_dir is not None:
            return space.call_function(w_dir)
        return space.call_function(space.w_list, w_dict)

    # lazy initialization of __annotations__ if not present

    def descr_get_annotations(self, space):
        w_dict = self.w_dict
        w_ann = space.finditem(w_dict, space.newtext('__annotations__'))
        if w_ann is None:
            w_ann = space.newdict()
            space.setitem(w_dict, space.newtext('__annotations__'), w_ann)
        return w_ann

    def descr_set_annotations(self, space, w_ann):
        space.setitem(self.w_dict, space.newtext('__annotations__'), w_ann)

    def descr_del_annotations(self, space):
        w_dict = self.w_dict
        w_ann = space.finditem(w_dict, space.newtext('__annotations__'))
        if w_ann is None:
            raise oefmt(space.w_AttributeError, "__annotations__")
        space.delitem(w_dict, space.newtext('__annotations__'))

    # These three methods are needed to implement '__class__' assignment
    # between a module and a subclass of module.  They give every module
    # the ability to have its '__class__' set, manually.  Note that if
    # you instantiate a subclass of ModuleType in the first place, then
    # you get an RPython instance of a subclass of Module created in the
    # normal way by typedef.py.  That instance has got its own
    # getclass(), getslotvalue(), etc. but provided it has no __slots__,
    # it is compatible with ModuleType for '__class__' assignment.

    def getclass(self, space):
        if self.w_userclass is None:
            return W_Root.getclass(self, space)
        return self.w_userclass

    def setclass(self, space, w_cls):
        self.w_userclass = w_cls

    def user_setup(self, space, w_subtype):
        self.w_userclass = w_subtype


def init_extra_module_attrs(space, w_mod):
    w_dict = w_mod.getdict(space)
    if w_dict is None:
        return
    for extra in ['__package__', '__loader__', '__spec__']:
        w_attr = space.new_interned_str(extra)
        space.call_method(w_dict, 'setdefault', w_attr, space.w_None)