Skip to content

Commit

Permalink
Merge tpmodules-py3-7804-3: Port twisted.python.modules to Python3
Browse files Browse the repository at this point in the history
Author: hawkowl
Reviewer: adiroiban
Fixes: twisted#7804

git-svn-id: svn://svn.twistedmatrix.com/svn/Twisted/trunk@44338 bbbe8e31-12d6-0310-92fd-ac37d47ddeeb
  • Loading branch information
hawkowl committed Mar 31, 2015
1 parent 24ab25e commit 38ae371
Show file tree
Hide file tree
Showing 6 changed files with 102 additions and 70 deletions.
1 change: 1 addition & 0 deletions LICENSE
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ Ralph Meijer
Richard Wall
Sean Riley
Software Freedom Conservancy
Tavendo GmbH
Travis B. Hartwell
Thijs Triemstra
Thomas Herve
Expand Down
2 changes: 2 additions & 0 deletions twisted/python/dist3.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@
"twisted.python.randbytes",
"twisted.python.reflect",
"twisted.python.runtime",
"twisted.python.modules",
"twisted.python.systemd",
"twisted.python.test",
"twisted.python.test.deprecatedattributes",
Expand Down Expand Up @@ -198,6 +199,7 @@
"twisted.test.test_randbytes",
"twisted.test.test_reflect",
"twisted.test.test_setup",
"twisted.test.test_modules",
"twisted.test.test_ssl",
"twisted.test.test_sslverify",
"twisted.test.test_task",
Expand Down
91 changes: 51 additions & 40 deletions twisted/python/modules.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,22 +53,30 @@
modinfo.name, modinfo.filePath.path)
"""

from __future__ import division, absolute_import

__metaclass__ = type

# let's try to keep path imports to a minimum...
from os.path import dirname, split as splitpath

import sys
import zipimport
import inspect
import warnings
from zope.interface import Interface, implementer

from twisted.python.compat import nativeString, _PY3
from twisted.python.components import registerAdapter
from twisted.python.filepath import FilePath, UnlistableError
from twisted.python.zippath import ZipArchive
from twisted.python.reflect import namedAny

if not _PY3:
# TODO: Zippath isn't ported yet.
# See https://tm.tl/#6917.
from twisted.python.zippath import ZipArchive
import zipimport


_nothing = object()

PYTHON_EXTENSIONS = ['.py']
Expand All @@ -82,13 +90,14 @@ def _isPythonIdentifier(string):
"""
cheezy fake test for proper identifier-ness.
@param string: a str which might or might not be a valid python identifier.
@param string: a L{str} which might or might not be a valid python
identifier.
@return: True or False
"""
return (' ' not in string and
'.' not in string and
'-' not in string)
textString = nativeString(string)
return (' ' not in textString and
'.' not in textString and
'-' not in textString)



Expand Down Expand Up @@ -127,11 +136,10 @@ def iterModules(self):

for placeToLook in self._packagePaths():
try:
children = placeToLook.children()
children = sorted(placeToLook.children())
except UnlistableError:
continue

children.sort()
for potentialTopLevel in children:
ext = potentialTopLevel.splitext()[1]
potentialBasename = potentialTopLevel.basename()[:-len(ext)]
Expand Down Expand Up @@ -310,8 +318,9 @@ def __init__(self, name, filePath, pathEntry):
@param filePath: see ivar
@param pathEntry: see ivar
"""
assert not name.endswith(".__init__")
self.name = name
_name = nativeString(name)
assert not _name.endswith(".__init__")
self.name = _name
self.filePath = filePath
self.parentPath = filePath.parent()
self.pathEntry = pathEntry
Expand Down Expand Up @@ -486,37 +495,39 @@ def mapPath(self, fsPathString):
_theDefaultMapper = _DefaultMapImpl()


if not _PY3:
@implementer(IPathImportMapper)
class _ZipMapImpl:
""" IPathImportMapper implementation for zipimport.ZipImporter. """
def __init__(self, importer):
self.importer = importer

def mapPath(self, fsPathString):
"""
Map the given FS path to a ZipPath, by looking at the ZipImporter's
"archive" attribute and using it as our ZipArchive root, then walking
down into the archive from there.
@return: a L{zippath.ZipPath} or L{zippath.ZipArchive} instance.
"""
za = ZipArchive(self.importer.archive)
myPath = FilePath(self.importer.archive)
itsPath = FilePath(fsPathString)
if myPath == itsPath:
return za
# This is NOT a general-purpose rule for sys.path or __file__:
# zipimport specifically uses regular OS path syntax in its
# pathnames, even though zip files specify that slashes are always
# the separator, regardless of platform.
segs = itsPath.segmentsFrom(myPath)
zp = za
for seg in segs:
zp = zp.child(seg)
return zp

registerAdapter(_ZipMapImpl, zipimport.zipimporter, IPathImportMapper)

@implementer(IPathImportMapper)
class _ZipMapImpl:
""" IPathImportMapper implementation for zipimport.ZipImporter. """
def __init__(self, importer):
self.importer = importer

def mapPath(self, fsPathString):
"""
Map the given FS path to a ZipPath, by looking at the ZipImporter's
"archive" attribute and using it as our ZipArchive root, then walking
down into the archive from there.
@return: a L{zippath.ZipPath} or L{zippath.ZipArchive} instance.
"""
za = ZipArchive(self.importer.archive)
myPath = FilePath(self.importer.archive)
itsPath = FilePath(fsPathString)
if myPath == itsPath:
return za
# This is NOT a general-purpose rule for sys.path or __file__:
# zipimport specifically uses regular OS path syntax in its pathnames,
# even though zip files specify that slashes are always the separator,
# regardless of platform.
segs = itsPath.segmentsFrom(myPath)
zp = za
for seg in segs:
zp = zp.child(seg)
return zp

registerAdapter(_ZipMapImpl, zipimport.zipimporter, IPathImportMapper)

def _defaultSysPathFactory():
"""
Expand Down
12 changes: 4 additions & 8 deletions twisted/python/test/modules_helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,17 +43,13 @@ def cleanUpSysModules():
sys.modules.update(sysModules)


def pathEntryWithOnePackage(self, pkgname=b"test_package"):
def pathEntryWithOnePackage(self, pkgname="test_package"):
"""
Generate a L{FilePath} with one package, named C{pkgname}, on it, and
return the L{FilePath} of the path entry.
"""
# Remove utf-8 encode and bytes for path segments when Filepath
# supports Unicode paths on Python 3 (#2366, #4736, #5203).
entry = FilePath(self.mktemp().encode("utf-8"))
pkg = entry.child(b"test_package")
entry = FilePath(self.mktemp())
pkg = entry.child("test_package")
pkg.makedirs()
pkg.child(b"__init__.py").setContent(b"")
pkg.child("__init__.py").setContent(b"")
return entry


65 changes: 43 additions & 22 deletions twisted/test/test_modules.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,28 @@
objects.
"""

from __future__ import division, absolute_import

import sys
import itertools
import zipfile
import compileall

import twisted
from twisted.trial.unittest import TestCase

from twisted.python import modules
from twisted.python.compat import _PY3, networkString
from twisted.python.filepath import FilePath
from twisted.python.reflect import namedAny

from twisted.trial.unittest import TestCase
from twisted.python.test.modules_helpers import TwistedModulesMixin
from twisted.python.test.test_zippath import zipit

if not _PY3:
# TODO: Zipfile support isn't ported yet.
# See https://tm.tl/#6917
import zipfile
from twisted.python.test.test_zippath import zipit



class TwistedModulesTestCase(TwistedModulesMixin, TestCase):
Expand Down Expand Up @@ -52,8 +60,8 @@ def test_namespacedPackages(self):
__import__('pkgutil')

namespaceBoilerplate = (
'import pkgutil; '
'__path__ = pkgutil.extend_path(__path__, __name__)')
b'import pkgutil; '
b'__path__ = pkgutil.extend_path(__path__, __name__)')

# Create two temporary directories with packages:
#
Expand Down Expand Up @@ -83,7 +91,7 @@ def test_namespacedPackages(self):
nestedEntry = testPackagePath.child('nested_package')
nestedEntry.makedirs()
nestedEntry.child('__init__.py').setContent(namespaceBoilerplate)
nestedEntry.child('module.py').setContent('')
nestedEntry.child('module.py').setContent(b'')

anotherEntry = self.pathEntryWithOnePackage()
anotherPackagePath = anotherEntry.child('test_package')
Expand All @@ -92,7 +100,7 @@ def test_namespacedPackages(self):
anotherNestedEntry = anotherPackagePath.child('nested_package')
anotherNestedEntry.makedirs()
anotherNestedEntry.child('__init__.py').setContent(namespaceBoilerplate)
anotherNestedEntry.child('module2.py').setContent('')
anotherNestedEntry.child('module2.py').setContent(b'')

self.replaceSysPath([entry.path, anotherEntry.path])

Expand All @@ -105,7 +113,7 @@ def test_namespacedPackages(self):
walkedNames = [
mod.name for mod in module.walkModules(importPackages=True)]
finally:
for module in sys.modules.keys():
for module in list(sys.modules.keys()):
if module.startswith('test_package'):
del sys.modules[module]

Expand Down Expand Up @@ -184,7 +192,7 @@ def test_nonDirectoryPaths(self):

nonDirectoryPath = FilePath(self.mktemp())
self.failIf(nonDirectoryPath.exists())
nonDirectoryPath.setContent("zip file or whatever\n")
nonDirectoryPath.setContent(b"zip file or whatever\n")

self.replaceSysPath([existentPath.path])

Expand Down Expand Up @@ -275,16 +283,16 @@ def _evilSmartPath(pathName):
def evilChildren():
# normally this order is random; let's make sure it always
# comes up .pyc-first.
x = originalChildren()
x = list(originalChildren())
x.sort()
x.reverse()
return x
o.children = evilChildren
return o
mypath.child("abcd.py").setContent('\n')
mypath.child("abcd.py").setContent(b'\n')
compileall.compile_dir(mypath.path, quiet=True)
# sanity check
self.assertEqual(len(mypath.children()), 2)
self.assertEqual(len(list(mypath.children())), 2)
pp._smartPath = _evilSmartPath
self.assertEqual(pp['abcd'].filePath,
mypath.child('abcd.py'))
Expand All @@ -300,7 +308,7 @@ def test_packageMissingPath(self):
pp = modules.PythonPath(sysPath=[mypath.path])
subpath = mypath.child("abcd")
subpath.createDirectory()
subpath.child("__init__.py").setContent('del __path__\n')
subpath.child("__init__.py").setContent(b'del __path__\n')
sys.path.append(mypath.path)
__import__("abcd")
try:
Expand All @@ -319,20 +327,20 @@ class PathModificationTest(TwistedModulesTestCase):
stuffing some code in it.
"""

_serialnum = itertools.count().next # used to generate serial numbers for
# package names.
_serialnum = itertools.count() # used to generate serial numbers for
# package names.

def setUp(self):
self.pathExtensionName = self.mktemp()
self.pathExtension = FilePath(self.pathExtensionName)
self.pathExtension.createDirectory()
self.packageName = "pyspacetests%d" % (self._serialnum(),)
self.packageName = "pyspacetests%d" % (next(self._serialnum),)
self.packagePath = self.pathExtension.child(self.packageName)
self.packagePath.createDirectory()
self.packagePath.child("__init__.py").setContent("")
self.packagePath.child("a.py").setContent("")
self.packagePath.child("b.py").setContent("")
self.packagePath.child("c__init__.py").setContent("")
self.packagePath.child("__init__.py").setContent(b"")
self.packagePath.child("a.py").setContent(b"")
self.packagePath.child("b.py").setContent(b"")
self.packagePath.child("c__init__.py").setContent(b"")
self.pathSetUp = False


Expand All @@ -346,9 +354,9 @@ def _underUnderPathTest(self, doImport=True):
moddir2 = self.mktemp()
fpmd = FilePath(moddir2)
fpmd.createDirectory()
fpmd.child("foozle.py").setContent("x = 123\n")
fpmd.child("foozle.py").setContent(b"x = 123\n")
self.packagePath.child("__init__.py").setContent(
"__path__.append(%r)\n" % (moddir2,))
networkString("__path__.append({0})\n".format(repr(moddir2))))
# Cut here
self._setupSysPath()
modinfo = modules.getModule(self.packageName)
Expand Down Expand Up @@ -501,3 +509,16 @@ def test_doesntContainModule(self):
"""
thePath = modules.PythonPath()
self.assertNotIn('bogusModule', thePath)


__all__ = ["BasicTests", "PathModificationTest", "RebindingTest",
"ZipPathModificationTest", "PythonPathTestCase"]

if _PY3:
__all3__ = ["BasicTests", "PathModificationTest", "RebindingTest",
"PythonPathTestCase"]
for name in __all__[:]:
if name not in __all3__:
__all__.remove(name)
del globals()[name]
del name, __all3__
1 change: 1 addition & 0 deletions twisted/topfiles/7804.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
twisted.python.modules is now ported to Python 3.

0 comments on commit 38ae371

Please sign in to comment.