File: module.py

package info (click to toggle)
pypy3 7.0.0%2Bdfsg-3
  • links: PTS, VCS
  • area: main
  • in suites: buster
  • size: 111,848 kB
  • sloc: python: 1,291,746; ansic: 74,281; asm: 5,187; cpp: 3,017; sh: 2,533; makefile: 544; xml: 243; lisp: 45; csh: 21; awk: 4
file content (179 lines) | stat: -rw-r--r-- 6,817 bytes parent folder | download
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
"""
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.newtuple([new_inst,
                                   space.newtuple([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
        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_name = space.finditem(self.w_dict, space.newtext('__name__'))
            if w_name is None:
                raise oefmt(space.w_AttributeError,
                    "module has no attribute %R", w_attr)
            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)
        return space.call_function(space.w_list, w_dict)

    # 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)