Skip to content

Commit eb161cf

Browse files
committed
mitogen: Refactor Importer.ALWAYS_BLACKLIST -> ImportPolicy.unsuitables
Populating ImportPolicy.unsuitables via ModuleReponder on the controller will allow the controller to dynamically add unsuitable prefixes it is aware of.
1 parent ff89a85 commit eb161cf

6 files changed

Lines changed: 56 additions & 41 deletions

File tree

mitogen/core.py

Lines changed: 9 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1319,18 +1319,22 @@ class ImportPolicy(object):
13191319
:param blocks:
13201320
Prefixes always denied by the responder, only local versions can be
13211321
used.
1322+
1323+
:param unsuitables:
1324+
Prefixes unsuitable to be served, e.g. because they're Python stdlib,
1325+
platform specific. An optimisation to reduce futile round trips.
13221326
"""
1323-
def __init__(self, overrides=(), blocks=()):
1327+
def __init__(self, overrides=(), blocks=(), unsuitables=()):
13241328
self.overrides = set(overrides)
13251329
self.blocks = set(blocks)
1326-
self._always = set(Importer.ALWAYS_BLACKLIST)
1330+
self.unsuitables = set(unsuitables)
13271331

13281332
def denied(self, fullname):
13291333
fullnames = frozenset(module_lineage(fullname))
13301334
if self.overrides and not self.overrides.intersection(fullnames):
13311335
return ModuleDeniedByOverridesError
1332-
if self.blocks.intersection(fullnames): return ModuleDeniedByBlocksError
1333-
if self._always.intersection(fullnames): return ModuleUnsuitableError
1336+
if self.blocks & fullnames: return ModuleDeniedByBlocksError
1337+
if self.unsuitables & fullnames: return ModuleUnsuitableError
13341338
return False
13351339

13361340
def denied_raise(self, fullname):
@@ -1381,29 +1385,6 @@ class Importer(object):
13811385
'utils',
13821386
]
13831387

1384-
ALWAYS_BLACKLIST = [
1385-
# 2.x generates needless imports for 'builtins', while 3.x does the
1386-
# same for '__builtin__'. The correct one is built-in, the other always
1387-
# a negative round-trip.
1388-
'builtins',
1389-
'__builtin__',
1390-
1391-
# On some Python releases (e.g. 3.8, 3.9) the subprocess module tries
1392-
# to import of this Windows-only builtin module.
1393-
'msvcrt',
1394-
1395-
# Python 2.x module that was renamed to _thread in 3.x.
1396-
# This entry avoids a roundtrip on 2.x -> 3.x.
1397-
'thread',
1398-
1399-
# org.python.core imported by copy, pickle, xml.sax; breaks Jython, but
1400-
# very unlikely to trigger a bug report.
1401-
'org',
1402-
]
1403-
1404-
if sys.version_info >= (3, 0):
1405-
ALWAYS_BLACKLIST += ['cStringIO']
1406-
14071388
def __init__(self, router, context, core_src, policy):
14081389
self._log = logging.getLogger('mitogen.importer')
14091390
self._context = context
@@ -4202,15 +4183,11 @@ def _setup_importer(self):
42024183
else:
42034184
core_src = None
42044185

4205-
policy = ImportPolicy(
4206-
self.config['import_overrides'],
4207-
self.config['import_blocks'],
4208-
)
42094186
importer = Importer(
42104187
self.router,
42114188
self.parent,
42124189
core_src,
4213-
policy,
4190+
ImportPolicy(*self.config['policy']),
42144191
)
42154192

42164193
self.importer = importer

mitogen/imports/__init__.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,3 +36,20 @@ def codeobj_imports(co):
3636
* `names`: tuple of names in `from mod import ..`.
3737
"""
3838
return _code_imports(co.co_code, co.co_consts, co.co_names)
39+
40+
41+
def unsuitables():
42+
"""
43+
Return module prefixes that are known to be unsuitable for ModuleResponder
44+
to serve, due to e.g. legacy, platform specific, stdlib.
45+
"""
46+
prefixes = {
47+
'__builtin__', # Python 2.x built-in Imported as __builtins__.
48+
'builtins', # Python 3.x built-in. Imported as __builtins__.
49+
'cPickle', # Python 2.x extension
50+
'cStringIO', # Python 2.x extension
51+
'msvcrt', # Windows only. Imported by subprocess in some versions.
52+
'org', # Jython only. Imported by copy, pickle, & xml.sax.
53+
'thread', # Python 2.x built-in. Renamed to _thread in 3.x
54+
}
55+
return prefixes

mitogen/master.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1402,7 +1402,10 @@ def __init__(self, broker=None, max_message_size=None):
14021402

14031403
def upgrade(self):
14041404
self.id_allocator = IdAllocator(self)
1405-
self.responder = ModuleResponder(self, mitogen.core.ImportPolicy())
1405+
policy = mitogen.core.ImportPolicy(
1406+
unsuitables=mitogen.imports.unsuitables(),
1407+
)
1408+
self.responder = ModuleResponder(self, policy)
14061409
self.resource_responder = ResourceResponder(self)
14071410
self.log_forwarder = LogForwarder(self)
14081411
self.route_monitor = mitogen.parent.RouteMonitor(router=self)

mitogen/parent.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1498,14 +1498,13 @@ def get_econtext_config(self):
14981498
assert self.options.max_message_size is not None
14991499
parent_ids = mitogen.parent_ids[:]
15001500
parent_ids.insert(0, mitogen.context_id)
1501-
if mitogen.is_master: import_policy = self._router.responder.policy
1502-
else: import_policy = self._router.importer.policy
1501+
if mitogen.is_master: policy = self._router.responder.policy
1502+
else: policy = self._router.importer.policy
15031503
return {
15041504
'parent_ids': parent_ids,
15051505
'context_id': self.context.context_id,
15061506
'debug': self.options.debug,
1507-
'import_blocks': list(import_policy.blocks),
1508-
'import_overrides': list(import_policy.overrides),
1507+
'policy': (policy.overrides, policy.blocks, policy.unsuitables),
15091508
'profiling': self.options.profiling,
15101509
'unidirectional': self.options.unidirectional,
15111510
'log_level': get_log_level(),

tests/importer_test.py

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
import mitogen.core
1313
import mitogen.utils
14+
import mitogen.imports
1415
from mitogen.core import b
1516

1617
import testlib
@@ -274,7 +275,9 @@ def test_sys_module_not_fetched(self):
274275

275276
class ImportPolicyTest(testlib.TestCase):
276277
def test_default(self):
277-
policy = mitogen.core.ImportPolicy()
278+
policy = mitogen.core.ImportPolicy(
279+
unsuitables=mitogen.imports.unsuitables(),
280+
)
278281
self.assertFalse(policy.denied('pkg'))
279282
self.assertFalse(policy.denied('pkg.mod'))
280283
self.assertFalse(policy.denied('otherpkg'))
@@ -283,7 +286,10 @@ def test_default(self):
283286
self.assertTrue(policy.denied('builtins'))
284287

285288
def test_overrides(self):
286-
policy = mitogen.core.ImportPolicy(overrides=['pkg'])
289+
policy = mitogen.core.ImportPolicy(
290+
overrides=['pkg'],
291+
unsuitables=mitogen.imports.unsuitables(),
292+
)
287293
self.assertFalse(policy.denied('pkg'))
288294
self.assertFalse(policy.denied('pkg.mod'))
289295
self.assertTrue(policy.denied('otherpkg'))
@@ -292,7 +298,10 @@ def test_overrides(self):
292298
self.assertTrue(policy.denied('builtins'))
293299

294300
def test_blocks(self):
295-
policy = mitogen.core.ImportPolicy(blocks=['pkg'])
301+
policy = mitogen.core.ImportPolicy(
302+
blocks=['pkg'],
303+
unsuitables=mitogen.imports.unsuitables(),
304+
)
296305
self.assertTrue(policy.denied('pkg'))
297306
self.assertTrue(policy.denied('pkg.mod'))
298307
self.assertFalse(policy.denied('otherpkg'))
@@ -301,7 +310,11 @@ def test_blocks(self):
301310
self.assertTrue(policy.denied('builtins'))
302311

303312
def test_overrides_and_blocks(self):
304-
policy = mitogen.core.ImportPolicy(overrides=['pkg'], blocks=['pkg'])
313+
policy = mitogen.core.ImportPolicy(
314+
overrides=['pkg'],
315+
blocks=['pkg'],
316+
unsuitables=mitogen.imports.unsuitables(),
317+
)
305318
self.assertTrue(policy.denied('pkg'))
306319
self.assertTrue(policy.denied('pkg.mod'))
307320
self.assertTrue(policy.denied('otherpkg'))

tests/imports_test.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,3 +128,9 @@ def test_scoped_try_except(self):
128128
(level, 'in_except_exception', ('x', 'z')),
129129
]
130130
self.assertEqual(list(self.func(co)), expected)
131+
132+
133+
class UnsuitablesTest(testlib.TestCase):
134+
def test_unsuitables(self):
135+
unsuitables = mitogen.imports.unsuitables()
136+
self.assertTrue({'__builtin__', 'builtins'} & unsuitables)

0 commit comments

Comments
 (0)