diff --git a/.gitignore b/.gitignore index 1a19527e..ede7afff 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,7 @@ *.pdb *.dll .waf-* +.waf3-* .lock-waf* diff --git a/b b/b index bdbea45c..1f82f91d 100755 --- a/b +++ b/b @@ -4,6 +4,8 @@ PYVER=2.7 PYVER2=27 +#PYVER=3.2 +#PYVER2=32 if [ "$OSTYPE" = "cygwin" ]; then $TOOLS/python$PYVER2/python.exe -u build.py "$@" diff --git a/build.py b/build.py index 29a8173f..dd636e88 100755 --- a/build.py +++ b/build.py @@ -5,6 +5,9 @@ # the Python extension mocdules. #--------------------------------------------------------------------------- +from __future__ import absolute_import + +import sys import glob import hashlib import optparse @@ -16,13 +19,17 @@ import sys import tarfile import tempfile import datetime -import urllib2 +if sys.version_info < (3,): + from urllib2 import urlopen +else: + from urllib.request import urlopen + from distutils.dep_util import newer, newer_group from buildtools.config import Config, msg, opj, posixjoin, loadETG, etg2sip, findCmd, \ phoenixDir, wxDir, copyIfNewer, copyFile, \ macFixDependencyInstallName, macSetLoaderNames, \ - getSvnRev, runcmd + getSvnRev, runcmd, textfile_open import buildtools.version as version @@ -226,17 +233,17 @@ def numCPUs(): """ # Linux, Unix and MacOS: if hasattr(os, "sysconf"): - if os.sysconf_names.has_key("SC_NPROCESSORS_ONLN"): + if "SC_NPROCESSORS_ONLN" in os.sysconf_names: # Linux & Unix: ncpus = os.sysconf("SC_NPROCESSORS_ONLN") if isinstance(ncpus, int) and ncpus > 0: return ncpus else: # OSX: p = subprocess.Popen("sysctl -n hw.ncpu", shell=True, stdout=subprocess.PIPE) - return p.stdout.read() + return int(p.stdout.read()) # Windows: - if os.environ.has_key("NUMBER_OF_PROCESSORS"): + if "NUMBER_OF_PROCESSORS" in os.environ: ncpus = int(os.environ["NUMBER_OF_PROCESSORS"]); if ncpus > 0: return ncpus @@ -376,7 +383,7 @@ def getSipCmd(): msg('Not found. Attempting to download...') url = '%s/sip-%s-%s%s.bz2' % (toolsURL, sipCurrentVersion, platform, ext) try: - connection = urllib2.urlopen(url) + connection = urlopen(url) msg('Connection successful...') data = connection.read() msg('Data downloaded...') @@ -391,7 +398,7 @@ def getSipCmd(): data = bz2.decompress(data) with open(cmd, 'wb') as f: f.write(data) - os.chmod(cmd, 0755) + os.chmod(cmd, 0o755) return getSipCmd() @@ -434,7 +441,7 @@ def getWafCmd(): msg('Not found. Attempting to download...') url = '%s/waf-%s' % (toolsURL, wafCurrentVersion) try: - connection = urllib2.urlopen(url) + connection = urlopen(url) msg('Connection successful...') data = connection.read() msg('Data downloaded...') @@ -562,7 +569,6 @@ def etg(options, args): if newer_group(deps, sipfile): runcmd('%s %s %s' % (PYTHON, script, flags)) - def sphinx(options, args): from sphinxtools.postprocess import SphinxIndexes, MakeHeadings, PostProcess, GenGallery @@ -714,7 +720,7 @@ def sip(options, args): def processSrc(src, keepHashLines=False): - with file(src, 'rt') as f: + with textfile_open(src, 'rt') as f: srcTxt = f.read() if keepHashLines: # Either just fix the pathnames in the #line lines... @@ -733,20 +739,20 @@ def sip(options, args): if not os.path.exists(dest): msg('%s is a new file, copying...' % os.path.basename(src)) srcTxt = processSrc(src, options.keep_hash_lines) - f = file(dest, 'wt') + f = textfile_open(dest, 'wt') f.write(srcTxt) f.close() continue srcTxt = processSrc(src, options.keep_hash_lines) - with file(dest, 'rt') as f: + with textfile_open(dest, 'rt') as f: destTxt = f.read() if srcTxt == destTxt: pass else: msg('%s is changed, copying...' % os.path.basename(src)) - f = file(dest, 'wt') + f = textfile_open(dest, 'wt') f.write(srcTxt) f.close() @@ -1008,7 +1014,7 @@ def setup_py(options, args): wxbuild.macFixupInstallNames(DESTDIR, PREFIX, BUILD_DIR) # and also adjust the dependency names in the wxPython extensions - for line in file("installed_files.txt"): + for line in open("installed_files.txt"): line = line.strip() if line.endswith('.so'): macFixDependencyInstallName(DESTDIR, PREFIX, line, BUILD_DIR) @@ -1043,6 +1049,8 @@ def waf_py(options, args): build_options.append('--verbose') if options.jobs: build_options.append('--jobs=%s' % options.jobs) + + build_options.append('--python=%s' % PYTHON) pwd = pushDir(phoenixDir()) cmd = '%s %s %s configure build %s' % (PYTHON, waf, ' '.join(build_options), options.extra_waf) diff --git a/buildtools/config.py b/buildtools/config.py index 3ed2e2e0..6d3b5074 100644 --- a/buildtools/config.py +++ b/buildtools/config.py @@ -16,7 +16,6 @@ import os import glob import fnmatch import tempfile -import commands import shutil import codecs import subprocess @@ -26,8 +25,6 @@ from distutils.dir_util import mkpath from distutils.dep_util import newer from distutils.spawn import spawn -reload(sys) -sys.setdefaultencoding('utf-8') runSilently = False @@ -98,7 +95,8 @@ class Configuration(object): self.CLEANUP = list() # load the version numbers into this instance's namespace - execfile(opj(os.path.split(__file__)[0], 'version.py'), self.__dict__) + versionfile = opj(os.path.split(__file__)[0], 'version.py') + myExecfile(versionfile, self.__dict__) # If we're doing a dated build then alter the VERSION strings if os.path.exists('DAILY_BUILD'): @@ -272,7 +270,7 @@ class Configuration(object): self.WXPLAT = '__WXMSW__' portcfg = '' else: - raise SystemExit, "Unknown WXPORT value: " + self.WXPORT + raise SystemExit("Unknown WXPORT value: " + self.WXPORT) self.cflags += portcfg.split() @@ -382,14 +380,18 @@ class Configuration(object): def build_locale_list(self, srcdir): # get a list of all files under the srcdir, to be used for install_data - def walk_helper(lst, dirname, files): - for f in files: - filename = opj(dirname, f) - if not os.path.isdir(filename): - lst.append( (dirname, [filename]) ) - file_list = [] - os.path.walk(srcdir, walk_helper, file_list) - return file_list + if sys.version_info[0] == 2: + def walk_helper(lst, dirname, files): + for f in files: + filename = opj(dirname, f) + if not os.path.isdir(filename): + lst.append( (dirname, [filename]) ) + file_list = [] + os.path.walk(srcdir, walk_helper, file_list) + return file_list + else: + # TODO: Python3 version using os.walk generator + return [] def find_data_files(self, srcdir, *wildcards, **kw): @@ -558,7 +560,7 @@ def loadETG(name): return self.__dict__ ns = _Namespace() - execfile(name, ns.nsdict()) + myExecfile(name, ns.nsdict()) return ns @@ -574,7 +576,7 @@ def _getSbfValue(etg, keyName): cfg = Config() sbf = opj(cfg.SIPOUT, etg.NAME + '.sbf') out = list() - for line in file(sbf): + for line in open(sbf): key, value = line.split('=') if key.strip() == keyName: return sorted([opj(cfg.SIPOUT, v) for v in value.strip().split()]) @@ -750,6 +752,8 @@ def runcmd(cmd, getOutput=False, echoCmd=True, fatal=True): output = None if getOutput: output = sp.stdout.read() + if sys.version_info > (3,): + output = output.decode('utf-8') # TODO: is utf-8 okay here? output = output.rstrip() rval = sp.wait() @@ -763,3 +767,22 @@ def runcmd(cmd, getOutput=False, echoCmd=True, fatal=True): return output +def myExecfile(filename, ns): + if sys.version_info < (3,): + execfile(filename, ns) + else: + source = open(filename, 'r').read() + exec(source, ns) + + +def textfile_open(filename, mode='rt'): + """ + Simple wrapper around open() that will open normally on Python 2.x and on + Python 2.3 will add the encoding parameter. The mode parameter must + include the 't' to put the stream into text mode. + """ + assert 't' in mode + if sys.version_info < (3,): + return open(filename, mode) + else: + return open(filename, mode, encoding='utf-8') diff --git a/buildtools/distutils_hacks.py b/buildtools/distutils_hacks.py index 1702ceb4..f28a737d 100644 --- a/buildtools/distutils_hacks.py +++ b/buildtools/distutils_hacks.py @@ -17,9 +17,9 @@ import distutils.command.install import distutils.command.install_data import distutils.command.install_headers import distutils.command.clean -from distutils.dep_util import newer, newer_group +from distutils.dep_util import newer, newer_group -from config import Config, posixjoin, loadETG, etg2sip +from .config import Config, posixjoin, loadETG, etg2sip @@ -231,8 +231,8 @@ class MyUnixCCompiler(distutils.unixccompiler.UnixCCompiler): try: self.spawn(compiler_so + cc_args + [src, '-o', obj] + extra_postargs) - except DistutilsExecError, msg: - raise CompileError, msg + except DistutilsExecError as msg: + raise CompileError(msg) _orig_parse_makefile = distutils.sysconfig.parse_makefile def _parse_makefile(filename, g=None): @@ -289,14 +289,14 @@ def _compile(self, obj, src, ext, cc_args, extra_postargs, pp_opts): #self.spawn(["windres", "-i", src, "-o", obj]) self.spawn(["windres", "-i", src, "-o", obj] + [arg for arg in cc_args if arg.startswith("-I")] ) - except DistutilsExecError, msg: - raise CompileError, msg + except DistutilsExecError as msg: + raise CompileError(msg) else: # for other files use the C-compiler try: self.spawn(self.compiler_so + cc_args + [src, '-o', obj] + extra_postargs) - except DistutilsExecError, msg: - raise CompileError, msg + except DistutilsExecError as msg: + raise CompileError(msg) distutils.cygwinccompiler.CygwinCCompiler._compile = _compile @@ -327,7 +327,7 @@ if os.name == 'nt' and sys.version_info >= (2,6): #---------------------------------------------------------------------- -from sipdistutils import build_ext +from .sipdistutils import build_ext class etgsip_build_ext(build_ext): """ diff --git a/etg/_adv.py b/etg/_adv.py index 3cca3d0b..def31750 100644 --- a/etg/_adv.py +++ b/etg/_adv.py @@ -84,7 +84,7 @@ def run(): module.addHeaderCode('#include ') module.addImport('_core') - module.addPyCode("import core as wx", order=10) + module.addPyCode("import wx", order=10) module.addInclude(INCLUDES) diff --git a/etg/_core.py b/etg/_core.py index 133e5c18..32b5bb44 100644 --- a/etg/_core.py +++ b/etg/_core.py @@ -404,7 +404,7 @@ def run(): ]) - module.addPreInitializerCode("""\ + module.addInitializerCode("""\ wxPyPreInit(sipModuleDict); """) diff --git a/etg/accel.py b/etg/accel.py index 20c8b0f1..41c876ab 100644 --- a/etg/accel.py +++ b/etg/accel.py @@ -79,7 +79,7 @@ def run(): PyObject* o1 = PySequence_ITEM(obj, 0); PyObject* o2 = PySequence_ITEM(obj, 1); PyObject* o3 = PySequence_ITEM(obj, 2); - tmpEntries[idx].Set(PyInt_AsLong(o1), PyInt_AsLong(o2), PyInt_AsLong(o3)); + tmpEntries[idx].Set(wxPyInt_AsLong(o1), wxPyInt_AsLong(o2), wxPyInt_AsLong(o3)); Py_DECREF(o1); Py_DECREF(o2); Py_DECREF(o3); diff --git a/etg/cmndata.py b/etg/cmndata.py index c9ef5d8e..a3484483 100644 --- a/etg/cmndata.py +++ b/etg/cmndata.py @@ -68,21 +68,21 @@ def run(): c.addCppMethod('PyObject*', 'GetPrivData', '()', """\ PyObject* data; wxPyBlock_t blocked = wxPyBeginBlockThreads(); - data = PyString_FromStringAndSize(self->GetPrivData(), - self->GetPrivDataLen()); + data = PyBytes_FromStringAndSize(self->GetPrivData(), + self->GetPrivDataLen()); wxPyEndBlockThreads(blocked); return data; """) c.addCppMethod('void', 'SetPrivData', '(PyObject* data)', """\ - if (! PyString_Check(data)) { + if (! PyBytes_Check(data)) { wxPyBLOCK_THREADS(PyErr_SetString(PyExc_TypeError, "Expected string object")); return /* NULL */ ; } wxPyBlock_t blocked = wxPyBeginBlockThreads(); - self->SetPrivData(PyString_AS_STRING(data), PyString_GET_SIZE(data)); + self->SetPrivData(PyBytes_AS_STRING(data), PyBytes_GET_SIZE(data)); wxPyEndBlockThreads(blocked); """) diff --git a/etg/colour.py b/etg/colour.py index 441dffe5..3a262a8c 100644 --- a/etg/colour.py +++ b/etg/colour.py @@ -185,7 +185,7 @@ def run(): return 1; if (sipCanConvertToType(sipPy, sipType_wxColour, SIP_NO_CONVERTORS)) return 1; - if (PyString_Check(sipPy) || PyUnicode_Check(sipPy)) + if (PyBytes_Check(sipPy) || PyUnicode_Check(sipPy)) return 1; if (PySequence_Check(sipPy)) { size_t len = PySequence_Size(sipPy); @@ -210,7 +210,7 @@ def run(): return sipGetState(sipTransferObj); } // Is it a string? - else if (PyString_Check(sipPy) || PyUnicode_Check(sipPy)) { + else if (PyBytes_Check(sipPy) || PyUnicode_Check(sipPy)) { wxString spec = Py2wxString(sipPy); if (spec.GetChar(0) == '#' && (spec.length() == 7 || spec.length() == 9)) { // It's #RRGGBB[AA] @@ -251,11 +251,11 @@ def run(): PyObject* o2 = PySequence_GetItem(sipPy, 1); PyObject* o3 = PySequence_GetItem(sipPy, 2); if (len == 3) - *sipCppPtr = new wxColour(PyInt_AsLong(o1), PyInt_AsLong(o2), PyInt_AsLong(o3)); + *sipCppPtr = new wxColour(wxPyInt_AsLong(o1), wxPyInt_AsLong(o2), wxPyInt_AsLong(o3)); else { PyObject* o4 = PySequence_GetItem(sipPy, 3); - *sipCppPtr = new wxColour(PyInt_AsLong(o1), PyInt_AsLong(o2), PyInt_AsLong(o3), - PyInt_AsLong(o4)); + *sipCppPtr = new wxColour(wxPyInt_AsLong(o1), wxPyInt_AsLong(o2), wxPyInt_AsLong(o3), + wxPyInt_AsLong(o4)); Py_DECREF(o4); } Py_DECREF(o1); diff --git a/etg/dataobj.py b/etg/dataobj.py index 9eeadea9..ac112b5c 100644 --- a/etg/dataobj.py +++ b/etg/dataobj.py @@ -165,7 +165,7 @@ def run(): if (!fmtObj) goto error; sizeObj = PyObject_CallMethod(self, "GetDataSize", "(O)", fmtObj, NULL); if (!sizeObj) goto error; - size = PyInt_AsSsize_t(sizeObj); + size = wxPyInt_AsSsize_t(sizeObj); // Make a buffer that big using the pointer passed to us, and then // call the Python method. @@ -237,7 +237,7 @@ def run(): sizeObj = PyObject_CallMethod(self, "GetDataSize", "", NULL); if (!sizeObj) goto error; - size = PyInt_AsSsize_t(sizeObj); + size = wxPyInt_AsSsize_t(sizeObj); // Make a buffer that big using the pointer passed to us, and then // call the Python method. diff --git a/etg/event.py b/etg/event.py index f1ff19ca..5541e7a9 100644 --- a/etg/event.py +++ b/etg/event.py @@ -106,7 +106,7 @@ def run(): PyFunctionDef('__init__', '(self, evtType, expectedIDs=0)', body="""\ if expectedIDs not in [0, 1, 2]: - raise ValueError, "Invalid number of expectedIDs" + raise ValueError("Invalid number of expectedIDs") self.expectedIDs = expectedIDs if isinstance(evtType, (list, tuple)): @@ -205,10 +205,11 @@ def run(): (entry->m_callbackUserData != NULL)) { wxPyCallback *cb = (wxPyCallback*)entry->m_callbackUserData; - wxPyBlock_t blocked = wxPyBeginBlockThreads(); - int result = PyObject_Compare(cb->m_func, func); - wxPyEndBlockThreads(blocked); - if (result == 0) { + //wxPyBlock_t blocked = wxPyBeginBlockThreads(); + //int result = PyObject_Compare(cb->m_func, func); + //wxPyEndBlockThreads(blocked); + //if (result == 0) { + if (cb->m_func == func) { delete cb; self->GetDynamicEventTable()->Erase(node); delete entry; diff --git a/etg/listctrl.py b/etg/listctrl.py index d891ec72..41b6b356 100644 --- a/etg/listctrl.py +++ b/etg/listctrl.py @@ -73,7 +73,7 @@ def run(): PyObject* result = PyEval_CallObject(func, args); Py_DECREF(args); if (result) { - retval = PyInt_AsLong(result); + retval = wxPyInt_AsLong(result); Py_DECREF(result); } diff --git a/etg/region.py b/etg/region.py index 76209514..f743bd0b 100644 --- a/etg/region.py +++ b/etg/region.py @@ -78,6 +78,7 @@ def run(): if self._iterator.HaveRects(): self._iterator.Next() return rect + __next__ = next # for Python 3 """) diff --git a/etg/stream.py b/etg/stream.py index 6a8acaa3..26ae4c94 100644 --- a/etg/stream.py +++ b/etg/stream.py @@ -118,7 +118,7 @@ def run(): } else { // Return the data as a string object. TODO: Py3 - obj = PyString_FromStringAndSize(buf, buf.GetDataLen()); + obj = PyBytes_FromStringAndSize(buf, buf.GetDataLen()); } wxPyEndBlockThreads(blocked); return obj; @@ -205,7 +205,7 @@ def run(): } wxPyBlock_t blocked = wxPyBeginBlockThreads(); PyList_Append(pylist, s); - i += PyString_Size(s); + i += PyBytes_Size(s); wxPyEndBlockThreads(blocked); } @@ -274,12 +274,12 @@ def run(): c.addCppMethod('void', 'write', '(PyObject* data)', """\ // We use only strings for the streams, not unicode - PyObject* str = PyObject_Str(data); + PyObject* str = PyObject_Bytes(data); if (! str) { PyErr_SetString(PyExc_TypeError, "Unable to convert to string"); return; } - self->Write(PyString_AS_STRING(str), PyString_GET_SIZE(str)); + self->Write(PyBytes_AS_STRING(str), PyBytes_GET_SIZE(str)); Py_DECREF(str); """) diff --git a/etg/window.py b/etg/window.py index 4c69e329..e734e79d 100644 --- a/etg/window.py +++ b/etg/window.py @@ -169,6 +169,8 @@ def run(): import wx.siplib return not wx.siplib.isdeleted(self) """) + c.addPyCode('Window.__bool__ = Window.__nonzero__') # For Python 3 + # MSW only. Do we want them wrapped? c.find('GetAccessible').ignore() diff --git a/etgtools/__init__.py b/etgtools/__init__.py index c4597975..51217cc8 100644 --- a/etgtools/__init__.py +++ b/etgtools/__init__.py @@ -13,7 +13,7 @@ them from the Doxygen XML, and producing wrapper code from them. """ import sys, os -from extractors import * +from .extractors import * #--------------------------------------------------------------------------- @@ -68,7 +68,7 @@ def parseDoxyXML(module, class_or_filename_list): if not os.path.exists(pathname): pathname = os.path.join(XMLSRC, class_or_filename) if verbose(): - print "Loading %s..." % pathname + print("Loading %s..." % pathname) _filesparsed.add(pathname) root = et.parse(pathname).getroot() diff --git a/etgtools/extractors.py b/etgtools/extractors.py index 229c2033..44545494 100644 --- a/etgtools/extractors.py +++ b/etgtools/extractors.py @@ -17,8 +17,9 @@ import os import pprint import xml.etree.ElementTree as et -from tweaker_tools import removeWxPrefix, magicMethods, \ - guessTypeInt, guessTypeFloat, guessTypeStr +from .tweaker_tools import removeWxPrefix, magicMethods, \ + guessTypeInt, guessTypeFloat, guessTypeStr, \ + textfile_open from sphinxtools.utilities import FindDescendants #--------------------------------------------------------------------------- @@ -571,7 +572,7 @@ class ParamDef(BaseDef): if element.find('defval') is not None: self.default = flattenNode(element.find('defval')) except: - print "error when parsing element:" + print("error when parsing element:") et.dump(element) raise #--------------------------------------------------------------------------- @@ -725,7 +726,7 @@ class ClassDef(BaseDef): def includeCppCode(self, filename): - self.addCppCode(file(filename).read()) + self.addCppCode(textfile_open(filename).read()) def addAutoProperties(self): @@ -823,9 +824,9 @@ class ClassDef(BaseDef): # only create the prop if a method with that name does not exist, and it is a valid name if starts_with_number: - print 'WARNING: Invalid property name %s for class %s' % (name, self.name) + print('WARNING: Invalid property name %s for class %s' % (name, self.name)) elif self.findItem(name): - print "WARNING: Method %s::%s already exists in C++ class API, can not create a property." % (self.name, name) + print("WARNING: Method %s::%s already exists in C++ class API, can not create a property." % (self.name, name)) else: self.items.append(prop) @@ -1307,7 +1308,7 @@ class ModuleDef(BaseDef): self.cppCode.append(code) def includeCppCode(self, filename): - self.addCppCode(file(filename).read()) + self.addCppCode(textfile_open(filename).read()) def addInitializerCode(self, code): if isinstance(code, list): @@ -1447,7 +1448,7 @@ class ModuleDef(BaseDef): """ Add a snippet of Python code from a file to the wrapper module. """ - text = file(filename).read() + text = textfile_open(filename).read() return self.addPyCode( "#" + '-=' * 38 + '\n' + ("# This code block was included from %s\n%s\n" % (filename, text)) + @@ -1487,7 +1488,11 @@ def flattenNode(node, rstrip=True): """ if node is None: return "" - if isinstance(node, basestring): + if sys.version_info < (3,): + strclass = basestring + else: + strclass = str + if isinstance(node, strclass): return node text = node.text or "" for n in node: @@ -1526,11 +1531,11 @@ def verbose(): def extractingMsg(kind, element, nameTag='name'): if verbose(): - print 'Extracting %s: %s' % (kind, element.find(nameTag).text) + print('Extracting %s: %s' % (kind, element.find(nameTag).text)) def skippingMsg(kind, element): if verbose(): - print 'Skipping %s: %s' % (kind, element.find('name').text) + print('Skipping %s: %s' % (kind, element.find('name').text)) #--------------------------------------------------------------------------- diff --git a/etgtools/generators.py b/etgtools/generators.py index a047e3e5..52a88662 100644 --- a/etgtools/generators.py +++ b/etgtools/generators.py @@ -11,6 +11,7 @@ Just some base classes and stubs for the various generators """ +import sys class WrapperGeneratorBase(object): def __init__(self): @@ -79,12 +80,37 @@ def nci(text, numSpaces=0, stripLeading=True): #--------------------------------------------------------------------------- -from StringIO import StringIO +if sys.version_info < (3,): + # For Python 2.x we'll convert any unicode text values to strings before + # adding them to the buffer + from StringIO import StringIO + class Utf8EncodingStream(StringIO): + def write(self, text): + if isinstance(text, unicode): + text = text.encode('utf-8') + return StringIO.write(self, text) -class Utf8EncodingStream(StringIO): - def write(self, text): - if isinstance(text, unicode): - text = text.encode('utf-8') - return StringIO.write(self, text) #super(EncodingStream, self).write(text) +else: + # For Python 3.x we'll keep it all as str (unicode) objects and let the + # conversion to bytes happen when the text is written to the actual + # file. + from io import StringIO + class Utf8EncodingStream(StringIO): + pass + + +def textfile_open(filename, mode='rt'): + """ + Simple wrapper around open() that will open normally on Python 2.x and on + Python 2.3 will add the encoding parameter. The mode parameter must + include the 't' to put the stream into text mode. + """ + assert 't' in mode + if sys.version_info < (3,): + return open(filename, mode) + else: + return open(filename, mode, encoding='utf-8') + + #--------------------------------------------------------------------------- diff --git a/etgtools/pi_generator.py b/etgtools/pi_generator.py index dc470ec4..9a3bc859 100644 --- a/etgtools/pi_generator.py +++ b/etgtools/pi_generator.py @@ -17,11 +17,11 @@ completion, displaying docstrings in the source assistant panel, etc. """ import sys, os, re -import extractors -import generators -from generators import nci, Utf8EncodingStream -from tweaker_tools import removeWxPrefix, magicMethods, \ - guessTypeInt, guessTypeFloat, guessTypeStr +import etgtools.extractors as extractors +import etgtools.generators as generators +from etgtools.generators import nci, Utf8EncodingStream, textfile_open +from etgtools.tweaker_tools import removeWxPrefix, magicMethods, \ + guessTypeInt, guessTypeFloat, guessTypeStr phoenixRoot = os.path.abspath(os.path.split(__file__)[0]+'/..') @@ -57,7 +57,7 @@ class PiWrapperGenerator(generators.WrapperGeneratorBase): if not os.path.exists(destFile): # create the file and write the header - f = file(destFile, 'wt') + f = textfile_open(destFile, 'wt') f.write(header) f.close() @@ -75,7 +75,7 @@ class PiWrapperGenerator(generators.WrapperGeneratorBase): sectionBeginMarker = '#-- begin-%s --#' % sectionName sectionEndMarker = '#-- end-%s --#' % sectionName - lines = file(destFile, 'rt').readlines() + lines = textfile_open(destFile, 'rt').readlines() for idx, line in enumerate(lines): if line.startswith(sectionBeginMarker): sectionBeginLine = idx @@ -91,9 +91,8 @@ class PiWrapperGenerator(generators.WrapperGeneratorBase): # replace the existing lines lines[sectionBeginLine+1:sectionEndLine] = [sectionText] - f = file(destFile, 'wt') + f = textfile_open(destFile, 'wt') f.writelines(lines) - #f.write('\n') f.close() diff --git a/etgtools/sip_generator.py b/etgtools/sip_generator.py index 0c40ee8c..74e36e2b 100644 --- a/etgtools/sip_generator.py +++ b/etgtools/sip_generator.py @@ -13,9 +13,9 @@ objects produced by the ETG scripts. """ import sys, os, re -import extractors -import generators -from generators import nci, Utf8EncodingStream +import etgtools.extractors as extractors +import etgtools.generators as generators +from etgtools.generators import nci, Utf8EncodingStream, textfile_open divider = '//' + '-'*75 + '\n' @@ -45,7 +45,7 @@ class SipWrapperGenerator(generators.WrapperGeneratorBase): # Write the contents of the stream to the destination file if not destFile: destFile = os.path.join(phoenixRoot, 'sip/gen', module.name + '.sip') - file(destFile, 'wt').write(stream.getvalue()) + textfile_open(destFile, 'wt').write(stream.getvalue()) #----------------------------------------------------------------------- @@ -90,7 +90,7 @@ class SipWrapperGenerator(generators.WrapperGeneratorBase): # Copyright: (c) 2011 by Total Control Software # License: wxWindows License %s -from %s import * +from .%s import * %%End diff --git a/etgtools/sphinx_generator.py b/etgtools/sphinx_generator.py index 7d34ec7c..7d586160 100644 --- a/etgtools/sphinx_generator.py +++ b/etgtools/sphinx_generator.py @@ -28,8 +28,8 @@ from StringIO import StringIO import xml.etree.ElementTree as et # Phoenix-specific stuff -import extractors -import generators +import etgtools.extractors as extractors +import etgtools.generators as generators # Sphinx-Phoenix specific stuff from sphinxtools.inheritance import InheritanceDiagram diff --git a/etgtools/tweaker_tools.py b/etgtools/tweaker_tools.py index 0beaf362..5bd3272b 100644 --- a/etgtools/tweaker_tools.py +++ b/etgtools/tweaker_tools.py @@ -12,7 +12,8 @@ Some helpers and utility functions that can assist with the tweaker stage of the ETG scripts. """ -import extractors +import etgtools as extractors +from .generators import textfile_open import sys, os import copy @@ -32,6 +33,7 @@ magicMethods = { # TODO: add more } + def removeWxPrefixes(node): """ Rename items with a 'wx' prefix to not have the prefix. If the back-end @@ -374,28 +376,28 @@ def getWrapperGenerator(): A simple factory function to create a wrapper generator class of the desired type. """ if '--swig' in sys.argv: - import swig_generator + from etgtools import swig_generator gClass = swig_generator.SwigWrapperGenerator elif '--sip' in sys.argv: - import sip_generator + from etgtools import sip_generator gClass = sip_generator.SipWrapperGenerator else: # The default is sip - import sip_generator + from etgtools import sip_generator gClass = sip_generator.SipWrapperGenerator return gClass() def getDocsGenerator(): if '--nodoc' in sys.argv: - import generators + from etgtools import generators return generators.StubbedDocsGenerator() elif '--sphinx' in sys.argv: - import sphinx_generator + from etgtools import sphinx_generator return sphinx_generator.SphinxGenerator() else: # the current default is sphinx - import sphinx_generator + from etgtools import sphinx_generator return sphinx_generator.SphinxGenerator() @@ -409,7 +411,7 @@ def runGenerators(module): generators.append(getWrapperGenerator()) # Toss in the PI generator too - import pi_generator + from etgtools import pi_generator generators.append(pi_generator.PiWrapperGenerator()) # And finally add the documentation generator @@ -425,7 +427,7 @@ def checkForUnitTestModule(module): pathname = 'unittests/test_%s.py' % module.name if os.path.exists(pathname) or not module.check4unittest: return - print 'WARNING: Unittest module (%s) not found!' % pathname + print('WARNING: Unittest module (%s) not found!' % pathname) #--------------------------------------------------------------------------- @@ -464,7 +466,7 @@ def convertTwoIntegersTemplate(CLASS): // or create a new instance PyObject* o1 = PySequence_ITEM(sipPy, 0); PyObject* o2 = PySequence_ITEM(sipPy, 1); - *sipCppPtr = new {CLASS}(PyInt_AsLong(o1), PyInt_AsLong(o2)); + *sipCppPtr = new {CLASS}(wxPyInt_AsLong(o1), wxPyInt_AsLong(o2)); Py_DECREF(o1); Py_DECREF(o2); return SIP_TEMPORARY; @@ -509,8 +511,8 @@ def convertFourIntegersTemplate(CLASS): PyObject* o2 = PySequence_ITEM(sipPy, 1); PyObject* o3 = PySequence_ITEM(sipPy, 2); PyObject* o4 = PySequence_ITEM(sipPy, 3); - *sipCppPtr = new {CLASS}(PyInt_AsLong(o1), PyInt_AsLong(o2), - PyInt_AsLong(o3), PyInt_AsLong(o4)); + *sipCppPtr = new {CLASS}(wxPyInt_AsLong(o1), wxPyInt_AsLong(o2), + wxPyInt_AsLong(o3), wxPyInt_AsLong(o4)); Py_DECREF(o1); Py_DECREF(o2); return SIP_TEMPORARY; @@ -724,7 +726,7 @@ del _{ListClass_pyName}___repr__ if (! PySequence_Check(sipPy)) success = FALSE; // ensure it is not a string or unicode object (they are sequences too) - else if (PyString_Check(sipPy) || PyUnicode_Check(sipPy)) + else if (PyBytes_Check(sipPy) || PyUnicode_Check(sipPy)) success = FALSE; // ensure each item can be converted to {ItemClass} else {{ @@ -871,7 +873,7 @@ static if (! PySequence_Check(source)) goto error0; // ensure it is not a string or unicode object (they are sequences too) - else if (PyString_Check(source) || PyUnicode_Check(source)) + else if (PyBytes_Check(source) || PyUnicode_Check(source)) goto error0; // ensure each item can be converted to {objType} else {{ diff --git a/samples/simple/hello.py b/samples/simple/hello.py index 7d846b8b..6deff2bd 100644 --- a/samples/simple/hello.py +++ b/samples/simple/hello.py @@ -1,15 +1,22 @@ -import wx -print wx.version() -#import os; print 'PID:', os.getpid(); raw_input('Ready to start, press enter...') - +import sys, os, wx +print(wx.version()); print(sys.version) + app = wx.App() frm = wx.Frame(None, title="Hello World!") - pnl = wx.Panel(frm) pnl.BackgroundColour = 'sky blue' -st = wx.StaticText(pnl, -1, 'This is wxPython\n%s' % wx.version(), (15,15)) + +st = wx.StaticText(pnl, -1, 'Hello World!', (15,10)) st.SetFont(wx.Font(14, wx.FONTFAMILY_SWISS, wx.FONTFLAG_BOLD)) +st = wx.StaticText(pnl, pos=(15,40), label= + 'This is wxPython %s\nrunning on Python %s' % + (wx.version(), sys.version.split(' ')[0])) +st.SetFont(wx.Font(10, wx.FONTFAMILY_SWISS, wx.FONTFLAG_BOLD)) + +bmp = wx.Bitmap(os.path.join(os.path.dirname(__file__), 'phoenix_main.png')) +sb = wx.StaticBitmap(pnl, label=bmp, pos=(15,85)) + frm.Show() app.MainLoop() diff --git a/samples/simple/phoenix_main.png b/samples/simple/phoenix_main.png new file mode 100644 index 00000000..a16468ba Binary files /dev/null and b/samples/simple/phoenix_main.png differ diff --git a/sphinxtools/constants.py b/sphinxtools/constants.py index ebaead80..6b1b73ad 100644 --- a/sphinxtools/constants.py +++ b/sphinxtools/constants.py @@ -184,7 +184,7 @@ class Enumeration(object): def __getattr__(self, attr): - if not self.lookup.has_key(attr): + if not attr in self.lookup: raise AttributeError return self.lookup[attr] diff --git a/sphinxtools/utilities.py b/sphinxtools/utilities.py index 5b8db747..cd5b7ebc 100644 --- a/sphinxtools/utilities.py +++ b/sphinxtools/utilities.py @@ -11,20 +11,24 @@ #--------------------------------------------------------------------------- # Standard library imports +import sys import os import codecs import shutil -import cPickle - -from UserDict import UserDict +if sys.version_info < (3,): + import cPickle as pickle + from UserDict import UserDict +else: + import pickle + from collections import UserDict # Phoenix-specific imports -from templates import TEMPLATE_CONTRIB +from .templates import TEMPLATE_CONTRIB -from constants import IGNORE, PUNCTUATION -from constants import CPP_ITEMS, VERSION, VALUE_MAP -from constants import RE_KEEP_SPACES, EXTERN_INHERITANCE -from constants import DOXYROOT, SPHINXROOT, WIDGETS_IMAGES_ROOT +from .constants import IGNORE, PUNCTUATION +from .constants import CPP_ITEMS, VERSION, VALUE_MAP +from .constants import RE_KEEP_SPACES, EXTERN_INHERITANCE +from .constants import DOXYROOT, SPHINXROOT, WIDGETS_IMAGES_ROOT # ----------------------------------------------------------------------- # @@ -577,14 +581,14 @@ def PickleItem(description, current_module, name, kind): if os.path.isfile(pickle_file): fid = open(pickle_file, 'rb') - items = cPickle.load(fid) + items = pickle.load(fid) fid.close() else: items = {} items[name] = description fid = open(pickle_file, 'wb') - cPickle.dump(items, fid) + pickle.dump(items, fid) fid.close() @@ -592,7 +596,7 @@ def PickleItem(description, current_module, name, kind): def PickleClassInfo(class_name, element, short_description): """ - Saves some information about a class in a cPickle-compatible file., i.e. the + Saves some information about a class in a pickle-compatible file., i.e. the list of methods in that class and its super-classes. :param string `class_name`: the name of the class we want to pickle; @@ -604,7 +608,7 @@ def PickleClassInfo(class_name, element, short_description): if os.path.isfile(pickle_file): fid = open(pickle_file, 'rb') - items = cPickle.load(fid) + items = pickle.load(fid) fid.close() else: items = {} @@ -618,7 +622,7 @@ def PickleClassInfo(class_name, element, short_description): items[class_name] = (method_list, bases, short_description) fid = open(pickle_file, 'wb') - cPickle.dump(items, fid) + pickle.dump(items, fid) fid.close() diff --git a/src/__init__.py b/src/__init__.py index 1f039c6b..06e78002 100644 --- a/src/__init__.py +++ b/src/__init__.py @@ -8,11 +8,11 @@ #--------------------------------------------------------------------------- # Load the main version string into the package namespace -import __version__ -__version__ = __version__.VERSION_STRING +import wx.__version__ +__version__ = wx.__version__.VERSION_STRING # Import all items from the core wxPython modules so they appear in the wx # package namespace. -from core import * +from wx.core import * diff --git a/src/app_ex.cpp b/src/app_ex.cpp index fb677138..d47296ca 100644 --- a/src/app_ex.cpp +++ b/src/app_ex.cpp @@ -194,20 +194,31 @@ void wxPyApp::_BootstrapApp() // Copy the values in Python's sys.argv list to a C array of char* to // be passed to the wxEntryStart function below. - int argc = 0; - char** argv = NULL; + #if PY_MAJOR_VERSION >= 3 + #define argType wchar_t + #else + #define argType char + #endif + int argc = 0; + argType** argv = NULL; blocked = wxPyBeginBlockThreads(); PyObject* sysargv = PySys_GetObject("argv"); if (sysargv != NULL) { argc = PyList_Size(sysargv); - argv = new char*[argc+1]; + argv = new argType*[argc+1]; int x; for(x=0; x= 3 + int len = PyObject_Length(pyArg); + argv[x] = new argType[len+1]; + wxPyUnicode_AsWideChar(pyArg, argv[x], len+1); + #else + argv[x] = strdup(PyBytes_AsString(pyArg)); + #endif } argv[argc] = NULL; } diff --git a/src/arrays.sip b/src/arrays.sip index 88021cc7..5c1d6a17 100644 --- a/src/arrays.sip +++ b/src/arrays.sip @@ -25,14 +25,14 @@ if (! PySequence_Check(sipPy)) success = FALSE; // Ensure it is not a string or unicode object (they are sequences) - else if (PyString_Check(sipPy) || PyUnicode_Check(sipPy)) + else if (PyBytes_Check(sipPy) || PyUnicode_Check(sipPy)) success = FALSE; // ensure each item is a string/unicode object else { Py_ssize_t i, len = PySequence_Length(sipPy); for (i=0; iAdd(PyInt_AS_LONG(number)); + array->Add(wxPyInt_AS_LONG(number)); Py_DECREF(item); Py_DECREF(number); } @@ -161,7 +160,7 @@ wxArrayString testArrayStringTypemap(const wxArrayString& arr); // Code to convert a wxArrayInt to a Python list of integers. PyObject* list = PyList_New(0); for (size_t i=0; i < sipCpp->GetCount(); i++) { - PyObject* number = PyInt_FromLong(sipCpp->Item(i)); + PyObject* number = wxPyInt_FromLong(sipCpp->Item(i)); PyList_Append(list, number); Py_DECREF(number); } diff --git a/src/core_ex.cpp b/src/core_ex.cpp index e9ecdd69..d48f1c0a 100644 --- a/src/core_ex.cpp +++ b/src/core_ex.cpp @@ -130,15 +130,15 @@ void wxPyCoreModuleInject(PyObject* moduleDict) // TODO: Find some blackmagic way to deprecate wx.Platform such that it raises // a wraning when used... Maybe a class that returns wx.Port for any __getattr__? - PyDict_SetItemString(moduleDict, "Port", PyString_FromString(wxPort)); - PyDict_SetItemString(moduleDict, "Platform", PyString_FromString(wxPort)); + PyDict_SetItemString(moduleDict, "Port", PyUnicode_FromString(wxPort)); + PyDict_SetItemString(moduleDict, "Platform", PyUnicode_FromString(wxPort)); // Make a tuple of strings that gives more info about the platform and build. PyObject* PlatformInfo = PyList_New(0); PyObject* obj; #define _AddInfoString(st) \ - obj = PyString_FromString(st); \ + obj = PyUnicode_FromString(st); \ PyList_Append(PlatformInfo, obj); \ Py_DECREF(obj) diff --git a/src/core_ex.py b/src/core_ex.py index df06f2cf..94462c20 100644 --- a/src/core_ex.py +++ b/src/core_ex.py @@ -1,26 +1,26 @@ +# Load version numbers from __version__... Ensure that major and minor +# versions are the same for both wxPython and wxWidgets. +if 'wxEVT_NULL' in dir(): + from wx.__version__ import * + import wx._core + __version__ = VERSION_STRING + assert MAJOR_VERSION == wx._core.MAJOR_VERSION, "wxPython/wxWidgets version mismatch" + assert MINOR_VERSION == wx._core.MINOR_VERSION, "wxPython/wxWidgets version mismatch" + if RELEASE_NUMBER != wx._core.RELEASE_NUMBER: + import warnings + warnings.warn("wxPython/wxWidgets release number mismatch") + del wx._core +else: + Port = '' + Platform = '' + PlatformInfo = [] + # A little trick to make 'wx' be a reference to this module so wx.Names can # be used in the python code here. import sys as _sys wx = _sys.modules[__name__] - -# Load version numbers from __version__... Ensure that major and minor -# versions are the same for both wxPython and wxWidgets. -if 'wxEVT_NULL' in dir(): - from __version__ import * - import _core - __version__ = VERSION_STRING - assert MAJOR_VERSION == _core.MAJOR_VERSION, "wxPython/wxWidgets version mismatch" - assert MINOR_VERSION == _core.MINOR_VERSION, "wxPython/wxWidgets version mismatch" - if RELEASE_NUMBER != _core.RELEASE_NUMBER: - import warnings - warnings.warn("wxPython/wxWidgets release number mismatch") - del _core -else: - Port = '' - Platform = '' - PlatformInfo = [] import warnings class wxPyDeprecationWarning(DeprecationWarning): @@ -29,6 +29,7 @@ class wxPyDeprecationWarning(DeprecationWarning): warnings.simplefilter('default', wxPyDeprecationWarning) del warnings + def deprecated(item, msg=''): """ Create a delegating wrapper that raises a deprecation warning. Can be @@ -86,7 +87,7 @@ def deprecated(item, msg=''): else: return DepGetProp(item, msg) else: - raise TypeError, "unsupported type %s" % type(item) + raise TypeError("unsupported type %s" % type(item)) #---------------------------------------------------------------------------- diff --git a/src/dataviewhelpers.sip b/src/dataviewhelpers.sip index 426a8d52..50046b0f 100644 --- a/src/dataviewhelpers.sip +++ b/src/dataviewhelpers.sip @@ -122,9 +122,9 @@ public: %ConvertToTypeCode // Code to test a PyObject for compatibility if (!sipIsErr) { - return PyLong_Check(sipPy) || PyInt_Check(sipPy); + return PyLong_Check(sipPy) || wxPyInt_Check(sipPy); } - if (PyLong_Check(sipPy) || PyInt_Check(sipPy)) + if (PyLong_Check(sipPy) || wxPyInt_Check(sipPy)) *sipCppPtrV = (wxPyLongPtr)PyLong_AsVoidPtr(sipPy); return sipGetState(sipTransferObj); diff --git a/src/event_ex.cpp b/src/event_ex.cpp index b63b678f..bcac6236 100644 --- a/src/event_ex.cpp +++ b/src/event_ex.cpp @@ -42,44 +42,11 @@ void wxPyCallback::EventThunker(wxEvent& event) { wxPyBlock_t blocked = wxPyBeginBlockThreads(); wxString className = event.GetClassInfo()->GetClassName(); - - // // If the event is one of these types then pass the original - // // event object instead of the one passed to us. - // if ( className == wxT("wxPyEvent") ) { - // arg = ((wxPyEvent*)&event)->GetSelf(); - // checkSkip = ((wxPyEvent*)&event)->GetCloned(); - // } - // else if ( className == wxT("wxPyCommandEvent") ) { - // arg = ((wxPyCommandEvent*)&event)->GetSelf(); - // checkSkip = ((wxPyCommandEvent*)&event)->GetCloned(); - // } - // else { - arg = wxPyConstructObject((void*)&event, className); - // } - + arg = wxPyConstructObject((void*)&event, className); if (!arg) { PyErr_Print(); } else { - // // "intern" the pre/post method names to speed up the HasAttr - // static PyObject* s_preName = NULL; - // static PyObject* s_postName = NULL; - // if (s_preName == NULL) { - // s_preName = PyString_FromString(wxPy_PRECALLINIT); - // s_postName = PyString_FromString(wxPy_POSTCALLCLEANUP); - // } - - // // Check if the event object needs some preinitialization - // if (PyObject_HasAttr(arg, s_preName)) { - // result = PyObject_CallMethodObjArgs(arg, s_preName, arg, NULL); - // if ( result ) { - // Py_DECREF(result); // result is ignored, but we still need to decref it - // PyErr_Clear(); // Just in case... - // } else { - // PyErr_Print(); - // } - // } - // Call the event handler, passing the event object tuple = PyTuple_New(1); PyTuple_SET_ITEM(tuple, 0, arg); // steals ref to arg @@ -90,30 +57,6 @@ void wxPyCallback::EventThunker(wxEvent& event) { } else { PyErr_Print(); } - - // // Check if the event object needs some post cleanup - // if (PyObject_HasAttr(arg, s_postName)) { - // result = PyObject_CallMethodObjArgs(arg, s_postName, arg, NULL); - // if ( result ) { - // Py_DECREF(result); // result is ignored, but we still need to decref it - // PyErr_Clear(); // Just in case... - // } else { - // PyErr_Print(); - // } - // } - - // if ( checkSkip ) { - // // if the event object was one of our special types and - // // it had been cloned, then we need to extract the Skipped - // // value from the original and set it in the clone. - // result = PyObject_CallMethod(arg, "GetSkipped", ""); - // if ( result ) { - // event.Skip(PyInt_AsLong(result)); - // Py_DECREF(result); - // } else { - // PyErr_Print(); - // } - // } Py_DECREF(tuple); } wxPyEndBlockThreads(blocked); diff --git a/src/stream_input.cpp b/src/stream_input.cpp index e525b494..824328cf 100644 --- a/src/stream_input.cpp +++ b/src/stream_input.cpp @@ -94,13 +94,13 @@ protected: Py_DECREF(arglist); size_t o = 0; - if ((result != NULL) && PyString_Check(result)) { - o = PyString_Size(result); + if ((result != NULL) && PyBytes_Check(result)) { + o = PyBytes_Size(result); if (o == 0) m_lasterror = wxSTREAM_EOF; if (o > bufsize) o = bufsize; - memcpy((char*)buffer, PyString_AsString(result), o); // strings only, not unicode... + memcpy((char*)buffer, PyBytes_AsString(result), o); // strings only, not unicode... Py_DECREF(result); } @@ -125,9 +125,9 @@ protected: // wxFileOffset is a 64-bit value... PyTuple_SET_ITEM(arglist, 0, PyLong_FromLongLong(off)); else - PyTuple_SET_ITEM(arglist, 0, PyInt_FromLong(off)); + PyTuple_SET_ITEM(arglist, 0, wxPyInt_FromLong(off)); - PyTuple_SET_ITEM(arglist, 1, PyInt_FromLong(mode)); + PyTuple_SET_ITEM(arglist, 1, wxPyInt_FromLong(mode)); PyObject* result = PyEval_CallObject(m_seek, arglist); @@ -148,7 +148,7 @@ protected: if (PyLong_Check(result)) o = PyLong_AsLongLong(result); else - o = PyInt_AsLong(result); + o = wxPyInt_AsLong(result); Py_DECREF(result); }; wxPyEndBlockThreads(blocked); diff --git a/src/stream_output.cpp b/src/stream_output.cpp index 4a191f90..2ba6e025 100644 --- a/src/stream_output.cpp +++ b/src/stream_output.cpp @@ -96,7 +96,7 @@ protected: wxPyBlock_t blocked = wxPyBeginBlockThreads(); PyObject* arglist = PyTuple_New(1); - PyTuple_SET_ITEM(arglist, 0, PyString_FromStringAndSize((char*)buffer, bufsize)); + PyTuple_SET_ITEM(arglist, 0, PyBytes_FromStringAndSize((char*)buffer, bufsize)); PyObject* result = PyEval_CallObject(m_write, arglist); Py_DECREF(arglist); @@ -118,9 +118,9 @@ protected: // wxFileOffset is a 64-bit value... PyTuple_SET_ITEM(arglist, 0, PyLong_FromLongLong(off)); else - PyTuple_SET_ITEM(arglist, 0, PyInt_FromLong(off)); + PyTuple_SET_ITEM(arglist, 0, wxPyInt_FromLong(off)); - PyTuple_SET_ITEM(arglist, 1, PyInt_FromLong(mode)); + PyTuple_SET_ITEM(arglist, 1, wxPyInt_FromLong(mode)); PyObject* result = PyEval_CallObject(m_seek, arglist); @@ -141,7 +141,7 @@ protected: if (PyLong_Check(result)) o = PyLong_AsLongLong(result); else - o = PyInt_AsLong(result); + o = wxPyInt_AsLong(result); Py_DECREF(result); }; wxPyEndBlockThreads(blocked); diff --git a/src/string.sip b/src/string.sip index bfea28c3..35d427f5 100644 --- a/src/string.sip +++ b/src/string.sip @@ -25,14 +25,14 @@ %ConvertToTypeCode // Code to test a PyObject for compatibility with wxString if (!sipIsErr) { - if (PyString_Check(sipPy) || PyUnicode_Check(sipPy)) + if (PyBytes_Check(sipPy) || PyUnicode_Check(sipPy)) return TRUE; return FALSE; } // Code to convert a compatible PyObject to a wxString PyObject* uni = sipPy; - if (PyString_Check(sipPy)) { + if (PyBytes_Check(sipPy)) { // if it's a string object convert it to unicode first, assuming utf-8 uni = PyUnicode_FromEncodedObject(sipPy, "utf-8", "strict"); if (PyErr_Occurred()) { @@ -43,10 +43,9 @@ *sipCppPtr = new wxString(); size_t len = PyUnicode_GET_SIZE(uni); if (len) { - PyUnicode_AsWideChar((PyUnicodeObject*)uni, - wxStringBuffer(**sipCppPtr, len), len); + wxPyUnicode_AsWideChar(uni, wxStringBuffer(**sipCppPtr, len), len); } - if (PyString_Check(sipPy)) + if (PyBytes_Check(sipPy)) Py_DECREF(uni); // release the temporary Unicode object we created return sipGetState(sipTransferObj); %End @@ -62,10 +61,10 @@ // Used just for testing the MappedType code, it can be removed later %ModuleCode -wxString _testStringTypemap(const wxString& str) +wxString testStringTypemap(const wxString& str) { wxString local = str; return local; } %End -wxString _testStringTypemap(const wxString& str); +wxString testStringTypemap(const wxString& str); diff --git a/src/variant.sip b/src/variant.sip index 2653fdca..7633bd1b 100644 --- a/src/variant.sip +++ b/src/variant.sip @@ -16,9 +16,9 @@ %ConvertToTypeCode // Code to test a PyObject for compatibility if (!sipIsErr) { - if (PyString_Check(sipPy) || PyUnicode_Check(sipPy)) + if (PyBytes_Check(sipPy) || PyUnicode_Check(sipPy)) return TRUE; - else if (PyInt_Check(sipPy) || PyLong_Check(sipPy)) + else if (wxPyInt_Check(sipPy) || PyLong_Check(sipPy)) return TRUE; else if (PyBool_Check(sipPy)) return TRUE; @@ -30,7 +30,7 @@ // Code to create a new wxPyUserData from the PyObject wxVariant* data = new wxVariant(); - if (PyString_Check(sipPy) || PyUnicode_Check(sipPy)) { + if (PyBytes_Check(sipPy) || PyUnicode_Check(sipPy)) { // TODO: Can we just reuse the code in string.sip somehow? // TODO: check state or iserr? @@ -38,8 +38,8 @@ wxString* strPtr = (wxString*)sipConvertToType(sipPy, sipType_wxString, NULL, SIP_NOT_NONE, NULL, &iserr); *data = *strPtr; } - else if (PyInt_Check(sipPy)) - *data = (long)PyInt_AS_LONG(sipPy); + else if (wxPyInt_Check(sipPy)) + *data = (long)wxPyInt_AS_LONG(sipPy); else if (PyLong_Check(sipPy)) *data = (long)PyLong_AsLong(sipPy); else if (PyBool_Check(sipPy)) { diff --git a/src/wxpy_api.h b/src/wxpy_api.h index d36c5b5a..b170f108 100644 --- a/src/wxpy_api.h +++ b/src/wxpy_api.h @@ -102,6 +102,35 @@ inline PyObject* wxPyMakeBuffer(void* ptr, Py_ssize_t len) { } +// Macros to work around differences in the Python 3 API +#if PY_MAJOR_VERSION >= 3 + #define wxPyInt_Check PyLong_Check + #define wxPyInt_AsLong PyLong_AsLong + #define wxPyInt_AS_LONG PyLong_AS_LONG + #define wxPyInt_AsSsize_t PyLong_AsSsize_t + #define wxPyInt_FromLong PyLong_FromLong + #define wxPyNumber_Int PyNumber_Long +#else + #define wxPyInt_Check PyInt_Check + #define wxPyInt_AsLong PyInt_AsLong + #define wxPyInt_AS_LONG PyInt_AS_LONG + #define wxPyInt_AsLong PyInt_AsLong + #define wxPyInt_AsSsize_t PyInt_AsSsize_t + #define wxPyInt_FromLong PyInt_FromLong + #define wxPyNumber_Int PyNumber_Int +#endif + +inline +Py_ssize_t wxPyUnicode_AsWideChar(PyObject* unicode, wchar_t* w, Py_ssize_t size) +{ +#if PY_MAJOR_VERSION >= 3 + return PyUnicode_AsWideChar(unicode, w, size); +#else + return PyUnicode_AsWideChar((PyUnicodeObject*)unicode, w, size); +#endif +} + + //-------------------------------------------------------------------------- // These are the API items whose implementation can not or should not be // inline functions or macros. The implementations will instead be accessed @@ -117,14 +146,18 @@ struct wxPyAPI { // Always add new items here at the end. }; + inline wxPyAPI* wxPyGetAPIPtr() { static wxPyAPI* wxPyAPIPtr = NULL; if (wxPyAPIPtr == NULL) { - wxPyAPIPtr = (wxPyAPI*)PyCObject_Import("wx._core", "_wxPyAPI"); + wxPyAPIPtr = (wxPyAPI*)PyCapsule_Import("wx._wxPyAPI", 0); + // uncomment if needed for debugging + //if (PyErr_Occurred()) { PyErr_Print(); } + //wxASSERT_MSG(wxPyAPIPtr != NULL, wxT("wxPyAPIPtr is NULL!!!")); } - // wxASSERT_MSG(wxPyAPIPtr != NULL, wxT("wxPyAPIPtr is NULL!!!")); // uncomment when needed for debugging + return wxPyAPIPtr; } @@ -147,6 +180,7 @@ inline PyObject* wxPyConstructObject(void* ptr, const wxString& className, bool // manipulations, PyDECREF's and etc. should be wrapped in calls to these functions: inline wxPyBlock_t wxPyBeginBlockThreads() { return wxPyGetAPIPtr()->p_wxPyBeginBlockThreads(); } + inline void wxPyEndBlockThreads(wxPyBlock_t blocked) { wxPyGetAPIPtr()->p_wxPyEndBlockThreads(blocked); } diff --git a/src/wxpy_api.sip b/src/wxpy_api.sip index beca3f95..09374456 100644 --- a/src/wxpy_api.sip +++ b/src/wxpy_api.sip @@ -28,7 +28,7 @@ static wxString i_Py2wxString(PyObject* source) { PyObject* uni = source; - if (PyString_Check(source)) { + if (PyBytes_Check(source)) { // if it's a string object convert it to unicode first, assumes utf-8 uni = PyUnicode_FromEncodedObject(source, "utf-8", "strict"); if (PyErr_Occurred()) { @@ -37,7 +37,11 @@ static wxString i_Py2wxString(PyObject* source) } } else if (!PyUnicode_Check(source)) { +#if PY_MAJOR_VERSION >= 3 + uni = PyObject_Str(source); +#else uni = PyObject_Unicode(source); +#endif if (PyErr_Occurred()) { PyErr_Clear(); return wxEmptyString; @@ -46,8 +50,7 @@ static wxString i_Py2wxString(PyObject* source) wxString target; size_t len = PyUnicode_GET_SIZE(uni); if (len) { - PyUnicode_AsWideChar((PyUnicodeObject*)uni, - wxStringBuffer(target, len), len); + wxPyUnicode_AsWideChar(uni, wxStringBuffer(target, len), len); } if (!PyUnicode_Check(source)) Py_DECREF(uni); // release the temporary Unicode object we created @@ -61,7 +64,7 @@ static wxString i_Py2wxString(PyObject* source) //inline wxString Py2wxString(PyObject* obj, bool setException=false, int& isErr=0) { // wxString str; // PyObject* uni = obj; -// if (PyString_Check(obj)) { +// if (PyBytes_Check(obj)) { // // if it's a string object convert it to unicode first, assuming utf-8 // uni = PyUnicode_FromEncodedObject(sipPy, "utf-8", "strict"); // if (PyErr_Occurred()) { @@ -77,7 +80,7 @@ static wxString i_Py2wxString(PyObject* source) // // TODO: Coerce non-unicode types to unicode here? (Classic does) // size_t len = PyUnicode_GET_SIZE(uni); // if (len) { -// PyUnicode_AsWideChar((PyUnicodeObject*)uni, wxStringBuffer(str, len), len); +// wxPyUnicode_AsWideChar(uni, wxStringBuffer(str, len), len); // } // if (obj != uni) // Py_DECREF(uni) // release the temporary Unicode object we may have created @@ -130,12 +133,15 @@ static wxPyAPI API = { %End -// Code that will run when _core is imported that will stash away a pointer -// to the structure. -%InitialisationCode - PyObject* cobj = PyCObject_FromVoidPtr(&API, NULL); - PyDict_SetItemString(sipModuleDict, "_wxPyAPI", cobj); - Py_XDECREF(cobj); +%PostInitialisationCode + // Code that will run when _core is imported that will stash away a + // pointer to the API structure. + PyObject* wxmod = PyImport_ImportModule("wx"); + PyObject* wxmodDict = PyModule_GetDict(wxmod); + PyObject* apiObj = PyCapsule_New(&API, "wx._wxPyAPI", NULL); + PyDict_SetItemString(wxmodDict, "_wxPyAPI", apiObj); + Py_XDECREF(apiObj); + Py_DECREF(wxmod); wxPyGetAPIPtr(); %End diff --git a/unittests/process_test.py b/unittests/process_test.py index 123a76ac..07f5e864 100644 --- a/unittests/process_test.py +++ b/unittests/process_test.py @@ -1,9 +1,9 @@ import sys if '--stdout' in sys.argv: - print 'process_test' + print('process_test') if '--echo' in sys.argv: text = raw_input() - print "I read '%s'" % text + print("I read '%s'" % text) sys.exit(0) diff --git a/unittests/runtests.py b/unittests/runtests.py index b530232a..b10a9b19 100755 --- a/unittests/runtests.py +++ b/unittests/runtests.py @@ -14,9 +14,9 @@ sys.path.insert(0, phoenixDir) # stuff for debugging import wx -print "wx.version:", wx.version() -print "pid:", os.getpid() -#print "executable:", sys.executable; raw_input("Press Enter...") +print("wx.version: " + wx.version()) +print("pid: " + str(os.getpid())) +#print("executable: " + sys.executable); raw_input("Press Enter...") import imp_unittest, unittest diff --git a/unittests/test_aboutdlg.py b/unittests/test_aboutdlg.py index 3493c375..1e2ed5aa 100644 --- a/unittests/test_aboutdlg.py +++ b/unittests/test_aboutdlg.py @@ -10,7 +10,7 @@ class aboutdlg_Tests(wtc.WidgetTestCase): def _makeInfo(self): info = wx.adv.AboutDialogInfo() info.SetVersion('1.2.3') - info.SetName('My Goofy App') + info.SetName('My Goofy AboutBox Test') info.SetDevelopers(['Goofy', 'Mickey', 'Donald']) info.SetDescription('This is a very goofy application') info.SetCopyright('(c) by Goofy Enterprises, Inc.') diff --git a/unittests/test_arraystring.py b/unittests/test_arraystring.py index 46cfdfd5..b53e3117 100644 --- a/unittests/test_arraystring.py +++ b/unittests/test_arraystring.py @@ -1,25 +1,32 @@ import imp_unittest, unittest import wx - +import wtc +import sys #--------------------------------------------------------------------------- +if not wtc.isPython3(): + alt = unicode +else: + def alt(s): + return bytes(s, 'utf-8') + class ArrayString(unittest.TestCase): if hasattr(wx, 'testArrayStringTypemap'): def test_ArrayStringTypemaps(self): # basic conversion of list or tuples of strings - seqList = ['a', u'b', 'hello world'] - self.assertEqual(wx.testArrayStringTypemap(seqList), seqList) - seqTuple = ('a', u'b', 'hello world') - self.assertEqual(wx.testArrayStringTypemap(seqTuple), list(seqTuple)) + seqList = ['a', alt('b'), 'hello world'] + self.assertEqual(wx.testArrayStringTypemap(seqList), ['a', 'b', 'hello world']) + seqTuple = ('a', alt('b'), 'hello world') + self.assertEqual(wx.testArrayStringTypemap(seqTuple), ['a', 'b', 'hello world']) def test_ArrayStringTypemapErrors(self): # test error conditions with self.assertRaises(TypeError): wx.testArrayStringTypemap("STRING sequence") with self.assertRaises(TypeError): - wx.testArrayStringTypemap(u"UNICODE sequence") + wx.testArrayStringTypemap(alt("ALT sequence")) with self.assertRaises(TypeError): wx.testArrayStringTypemap(["list", "with", "non-string", "items", 123]) diff --git a/unittests/test_bitmap.py b/unittests/test_bitmap.py index 72302620..2198be3f 100644 --- a/unittests/test_bitmap.py +++ b/unittests/test_bitmap.py @@ -57,7 +57,10 @@ class BitmapTests(wtc.WidgetTestCase): self.assertTrue( not b1.IsOk() ) b2 = wx.Bitmap(5, 10, 24) self.assertTrue( b2.IsOk() ) - self.assertTrue( b2.__nonzero__() == b2.IsOk() ) + if wtc.isPython3(): + self.assertTrue( b2.__bool__() == b2.IsOk() ) + else: + self.assertTrue( b2.__nonzero__() == b2.IsOk() ) # check that the __nonzero__ method can be used with if satements nzcheck = False diff --git a/unittests/test_cmndata.py b/unittests/test_cmndata.py index d0259d6a..f16131f9 100644 --- a/unittests/test_cmndata.py +++ b/unittests/test_cmndata.py @@ -36,9 +36,14 @@ class cmndata_tests(wtc.WidgetTestCase): pd = wx.PrintData() pdd = wx.PrintDialogData() - psdd.__nonzero__() - pd.__nonzero__() - pdd.__nonzero__() + if wtc.isPython3(): + psdd.__bool__() + pd.__bool__() + pdd.__bool__() + else: + psdd.__nonzero__() + pd.__nonzero__() + pdd.__nonzero__() #--------------------------------------------------------------------------- diff --git a/unittests/test_cursor.py b/unittests/test_cursor.py index a57a04c2..f47773e9 100644 --- a/unittests/test_cursor.py +++ b/unittests/test_cursor.py @@ -69,7 +69,10 @@ class CursorTests(wtc.WidgetTestCase): c2 = wx.Cursor(wx.CURSOR_ARROW) self.assertTrue( c2.IsOk() ) - self.assertTrue( c2.__nonzero__() == c2.IsOk() ) + if wtc.isPython3(): + self.assertTrue( c2.__bool__() == c2.IsOk() ) + else: + self.assertTrue( c2.__nonzero__() == c2.IsOk() ) # check that the __nonzero__ method can be used with if satements nzcheck = False diff --git a/unittests/test_dataobj.py b/unittests/test_dataobj.py index 3a3e438a..e347663d 100644 --- a/unittests/test_dataobj.py +++ b/unittests/test_dataobj.py @@ -68,7 +68,7 @@ class DataObjTests(wtc.WidgetTestCase): def __init__(self, value=''): wx.DataObject.__init__(self) self.myFormats = [wx.DataFormat(wx.DF_TEXT)] - self.myData = bytes(value) + self.myData = wtc.mybytes(value) def GetAllFormats(self, d): return self.myFormats @@ -120,7 +120,7 @@ class DataObjTests(wtc.WidgetTestCase): def __init__(self, value=''): wx.DataObjectSimple.__init__(self) self.SetFormat(wx.DataFormat(wx.DF_TEXT)) - self.myData = bytes(value) + self.myData = wtc.mybytes(value) def GetDataSize(self): return len(self.myData) @@ -155,11 +155,11 @@ class DataObjTests(wtc.WidgetTestCase): def test_CustomDataObject(self): import pickle - data1 = range(10) + data1 = list(range(10)) obj = wx.CustomDataObject('my custom format') obj.SetData(pickle.dumps(data1)) data2 = pickle.loads(obj.GetData().tobytes()) - self.assertTrue(data1 == data2) + self.assertEqual(data1, data2) diff --git a/unittests/test_display.py b/unittests/test_display.py index 2494b088..fbb946af 100644 --- a/unittests/test_display.py +++ b/unittests/test_display.py @@ -1,7 +1,7 @@ import imp_unittest, unittest import wtc import wx -import os; print os.getpid() +#import os; print(os.getpid()) #--------------------------------------------------------------------------- diff --git a/unittests/test_dnd.py b/unittests/test_dnd.py index 8526d2f1..08e2df06 100644 --- a/unittests/test_dnd.py +++ b/unittests/test_dnd.py @@ -39,7 +39,7 @@ class dnd_Tests(wtc.WidgetTestCase): if 'wxGTK' in wx.PlatformInfo: ds.SetIcon(wx.DragCopy, wx.Icon(icoFile)) else: - ds.SetCursor(wx.DragCopy, wx.Cursor(curFile)) + ds.SetCursor(wx.DragCopy, wx.Cursor(curFile, wx.BITMAP_TYPE_CUR)) #--------------------------------------------------------------------------- diff --git a/unittests/test_filesys.py b/unittests/test_filesys.py index f2eb9afc..8214b082 100644 --- a/unittests/test_filesys.py +++ b/unittests/test_filesys.py @@ -2,7 +2,6 @@ import imp_unittest, unittest import wtc import wx import os -from cStringIO import StringIO #--------------------------------------------------------------------------- diff --git a/unittests/test_image.py b/unittests/test_image.py index c2fa78e4..3b8d5b20 100644 --- a/unittests/test_image.py +++ b/unittests/test_image.py @@ -2,6 +2,10 @@ import imp_unittest, unittest import wtc import wx import os +if wtc.isPython3(): + from io import BytesIO as FileLikeObject +else: + from cStringIO import StringIO as FileLikeObject pngFile = os.path.join(os.path.dirname(__file__), 'toucan.png') @@ -75,16 +79,16 @@ class image_Tests(wtc.WidgetTestCase): self.assertTrue(img.IsOk()) def test_imageCtor8(self): - data = open(pngFile, 'rb').read() - import StringIO - stream = StringIO.StringIO(data) + with open(pngFile, 'rb') as f: + data = f.read() + stream = FileLikeObject(data) img = wx.Image(stream, wx.BITMAP_TYPE_PNG) self.assertTrue(img.IsOk()) def test_imageCtor9(self): - data = open(pngFile, 'rb').read() - import StringIO - stream = StringIO.StringIO(data) + with open(pngFile, 'rb') as f: + data = f.read() + stream = FileLikeObject(data) img = wx.Image(stream, 'image/png') self.assertTrue(img.IsOk()) @@ -133,9 +137,9 @@ class image_Tests(wtc.WidgetTestCase): self.assertTrue(img.IsOk()) data = img.GetDataBuffer() self.assertTrue(isinstance(data, memoryview)) - data[0] = '\1' - data[1] = '\2' - data[2] = '\3' + data[0] = b'\1' + data[1] = b'\2' + data[2] = b'\3' self.assertEqual(1, img.GetRed(0,0)) self.assertEqual(2, img.GetGreen(0,0)) self.assertEqual(3, img.GetBlue(0,0)) @@ -147,9 +151,9 @@ class image_Tests(wtc.WidgetTestCase): self.assertTrue(img.IsOk()) data = img.GetAlphaBuffer() self.assertTrue(isinstance(data, memoryview)) - data[0] = '\1' - data[1] = '\2' - data[2] = '\3' + data[0] = b'\1' + data[1] = b'\2' + data[2] = b'\3' self.assertEqual(1, img.GetAlpha(0,0)) self.assertEqual(2, img.GetAlpha(1,0)) self.assertEqual(3, img.GetAlpha(2,0)) diff --git a/unittests/test_joystick.py b/unittests/test_joystick.py index 2b69d217..73825c32 100644 --- a/unittests/test_joystick.py +++ b/unittests/test_joystick.py @@ -27,9 +27,11 @@ class joystick_Tests(wtc.WidgetTestCase): wx.EVT_JOY_ZMOVE wx.EVT_JOYSTICK_EVENTS - + + @unittest.expectedFailure def test_joystick2(self): # Creating a Joystick object should fail on Mac. Currently it isn't... + # We'll need a new feature added to sip to get it. if 'wxMac' in wx.PlatformInfo: with self.assertRaises(NotImplementedError): j = wx.adv.Joystick() diff --git a/unittests/test_mimetype.py b/unittests/test_mimetype.py index 527704d4..d56d994c 100644 --- a/unittests/test_mimetype.py +++ b/unittests/test_mimetype.py @@ -8,15 +8,17 @@ class mimetype_Tests(wtc.WidgetTestCase): def test_mimetype1(self): ft = wx.TheMimeTypesManager.GetFileTypeFromExtension('*.pdf') - ft.GetExtensions() - ft.GetMimeType() - ft.GetIcon() + if ft: + ft.GetExtensions() + ft.GetMimeType() + ft.GetIcon() def test_mimetype2(self): ft = wx.TheMimeTypesManager.GetFileTypeFromMimeType('image/png') - ft.GetExtensions() - ft.GetMimeType() - ft.GetIcon() + if ft: + ft.GetExtensions() + ft.GetMimeType() + ft.GetIcon() def test_mimetype3(self): fti = wx.FileTypeInfo('mime', 'open', 'print', 'desc', 'ext1') diff --git a/unittests/test_pickers.py b/unittests/test_pickers.py index 8659e8e2..585bc02c 100644 --- a/unittests/test_pickers.py +++ b/unittests/test_pickers.py @@ -7,7 +7,7 @@ import wx class pickers_Tests(wtc.WidgetTestCase): def test_pickersColour(self): - p = wx.ColourPickerCtrl(self.frame, col='blue') + p = wx.ColourPickerCtrl(self.frame, colour='blue') self.assertTrue(p.GetColour() == wx.Colour(0, 0, 0xff)) def test_pickersColourConstants(self): diff --git a/unittests/test_sound.py b/unittests/test_sound.py index 4ce8a3fc..efcfa74e 100644 --- a/unittests/test_sound.py +++ b/unittests/test_sound.py @@ -24,7 +24,8 @@ class sound_Tests(wtc.WidgetTestCase): def test_sound3(self): sound = wx.adv.Sound() self.assertTrue(not sound.IsOk()) - data = open(wavFile, 'rb').read() + with open(wavFile, 'rb') as f: + data = f.read() sound.CreateFromData(data) self.assertTrue(sound.IsOk()) rv = sound.Play(wx.adv.SOUND_SYNC) diff --git a/unittests/test_stream.py b/unittests/test_stream.py index 62134fe1..4c70172b 100644 --- a/unittests/test_stream.py +++ b/unittests/test_stream.py @@ -2,7 +2,10 @@ import imp_unittest, unittest import wtc import wx import os -from cStringIO import StringIO +if wtc.isPython3(): + from io import BytesIO as FileLikeObject +else: + from cStringIO import StringIO as FileLikeObject pngFile = os.path.join(os.path.dirname(__file__), 'toucan.png') @@ -16,7 +19,9 @@ class stream_Tests(wtc.WidgetTestCase): # wrapped function expecting a wxInputStream. # First, load the image data into a StringIO object - stream = StringIO(open(pngFile, 'rb').read()) + f = open(pngFile, 'rb') + stream = FileLikeObject(f.read()) + f.close() # Then use it to create a wx.Image img = wx.Image(stream) @@ -27,11 +32,11 @@ class stream_Tests(wtc.WidgetTestCase): # wrapped function expecting a wxOutputStream. image = wx.Image(pngFile) - stream = StringIO() + stream = FileLikeObject() image.SaveFile(stream, wx.BITMAP_TYPE_PNG) del image - stream = StringIO(stream.getvalue()) + stream = FileLikeObject(stream.getvalue()) image = wx.Image(stream) self.assertTrue(image.IsOk()) diff --git a/unittests/test_string.py b/unittests/test_string.py index 81ca3544..c9691214 100644 --- a/unittests/test_string.py +++ b/unittests/test_string.py @@ -1,61 +1,89 @@ import imp_unittest, unittest import wx -import wx._core +import wtc #--------------------------------------------------------------------------- + + class String(unittest.TestCase): - if hasattr(wx._core, '_testStringTypemap'): - def test_StringTypemaps(self): - utf = '\xc3\xa9l\xc3\xa9phant' # utf-8 string - uni = utf.decode('utf-8') # convert to unicode - iso = uni.encode('iso-8859-1') # make a string with a different encoding - - - # wx._testStringTypemap() will accept a parameter that is a Unicode object - # or an 'ascii' or 'utf-8' string object, which will then be converted to - # a wxString. The return value is a Unicode object that has been - # converted from a wxString that is a copy of the wxString created for - # the parameter. - - # ascii - result = wx._core._testStringTypemap('hello') - self.assertTrue(type(result) == unicode) - self.assertTrue(result == u'hello') - - # unicode should pass through unmodified - result = wx._core._testStringTypemap(uni) - self.assertTrue(result == uni) - - # utf-8 is converted - result = wx._core._testStringTypemap(utf) - self.assertTrue(result == uni) - - # can't auto-convert this - with self.assertRaises(UnicodeDecodeError): - result = wx._core._testStringTypemap(iso) + if hasattr(wx, 'testStringTypemap'): + if not wtc.isPython3(): + def test_StringTypemapsPy2(self): + utf = '\xc3\xa9l\xc3\xa9phant' # utf-8 string + uni = utf.decode('utf-8') # convert to unicode + iso = uni.encode('iso-8859-1') # make a string with a different encoding + - # utf-16-be - val = "\x00\xe9\x00l\x00\xe9\x00p\x00h\x00a\x00n\x00t" - with self.assertRaises(UnicodeDecodeError): - result = wx._core._testStringTypemap(val) - result = wx._core._testStringTypemap( val.decode('utf-16-be')) - self.assertTrue(result == uni) + # wx.testStringTypemap() will accept a parameter that + # is a Unicode object or an 'ascii' or 'utf-8' string object, + # which will then be converted to a wxString. The return + # value is a Unicode object that has been converted from a + # wxString that is a copy of the wxString created for the + # parameter. + + # ascii + result = wx.testStringTypemap('hello') + self.assertTrue(type(result) == unicode) + self.assertTrue(result == unicode('hello')) + + # unicode should pass through unmodified + result = wx.testStringTypemap(uni) + self.assertTrue(result == uni) + + # utf-8 is converted + result = wx.testStringTypemap(utf) + self.assertTrue(result == uni) + + # can't auto-convert this + with self.assertRaises(UnicodeDecodeError): + result = wx.testStringTypemap(iso) + + # utf-16-be + val = "\x00\xe9\x00l\x00\xe9\x00p\x00h\x00a\x00n\x00t" + with self.assertRaises(UnicodeDecodeError): + result = wx.testStringTypemap(val) + result = wx.testStringTypemap( val.decode('utf-16-be')) + self.assertTrue(result == uni) + + # utf-32-be + val = "\x00\x00\x00\xe9\x00\x00\x00l\x00\x00\x00\xe9\x00\x00\x00p\x00\x00\x00h\x00\x00\x00a\x00\x00\x00n\x00\x00\x00t" + with self.assertRaises(UnicodeDecodeError): + result = wx.testStringTypemap(val) + result = wx.testStringTypemap(val.decode('utf-32-be')) + self.assertTrue(result == uni) + + # utf-8 with BOM + #val = "\xef\xbb\xbfHello" + #result = wx.testStringTypemap(val) + #self.assertTrue(result == u'\ufeffHello') + + else: + def test_StringTypemapsPy3(self): + utf = b'\xc3\xa9l\xc3\xa9phant' # utf-8 bytes + uni = utf.decode('utf-8') # convert to unicode + iso = uni.encode('iso-8859-1') # make a string with a different encoding + + # ascii + result = wx.testStringTypemap(b'hello') + self.assertTrue(type(result) == str) + self.assertTrue(result == 'hello') + + # unicode should pass through unmodified + result = wx.testStringTypemap(uni) + self.assertTrue(result == uni) + + # utf-8 is converted + result = wx.testStringTypemap(utf) + self.assertTrue(result == uni) + + # can't auto-convert this + with self.assertRaises(UnicodeDecodeError): + result = wx.testStringTypemap(iso) + - # utf-32-be - val = "\x00\x00\x00\xe9\x00\x00\x00l\x00\x00\x00\xe9\x00\x00\x00p\x00\x00\x00h\x00\x00\x00a\x00\x00\x00n\x00\x00\x00t" - with self.assertRaises(UnicodeDecodeError): - result = wx._core._testStringTypemap(val) - result = wx._core._testStringTypemap(val.decode('utf-32-be')) - self.assertTrue(result == uni) - - # utf-8 with BOM - val = "\xef\xbb\xbfHello" - result = wx._core._testStringTypemap(val) - self.assertTrue(result == u'\ufeffHello') - #--------------------------------------------------------------------------- diff --git a/unittests/test_uiaction.py b/unittests/test_uiaction.py index 517423f8..4e67479e 100644 --- a/unittests/test_uiaction.py +++ b/unittests/test_uiaction.py @@ -179,11 +179,11 @@ class uiaction_KeyboardTests(wtc.WidgetTestCase): def test_uiactionKeyboardKeyDownUp(self): uia = wx.UIActionSimulator() for c in "This is a test": - if c in string.uppercase: + if c.isupper(): uia.KeyDown(wx.WXK_SHIFT); self.myYield() uia.KeyDown(ord(c)); self.myYield() uia.KeyUp(ord(c)); self.myYield() - if c in string.uppercase: + if c.isupper(): uia.KeyUp(wx.WXK_SHIFT); self.myYield() self.myYield() @@ -194,7 +194,7 @@ class uiaction_KeyboardTests(wtc.WidgetTestCase): uia = wx.UIActionSimulator() for c in "This is a test": mod = wx.MOD_NONE - if c in string.uppercase: + if c.isupper(): mod = wx.MOD_SHIFT uia.Char(ord(c), mod); self.myYield() self.myYield() diff --git a/unittests/test_window.py b/unittests/test_window.py index 350b7c7e..76f0b1f6 100644 --- a/unittests/test_window.py +++ b/unittests/test_window.py @@ -15,7 +15,11 @@ class WindowTests(wtc.WidgetTestCase): def test_windowHandle(self): w = wx.Window(self.frame, -1, (10,10), (50,50)) hdl = w.GetHandle() - self.assertTrue(isinstance(hdl, (int, long))) + if wtc.isPython3(): + base = int + else: + base = (int, long) + self.assertTrue(isinstance(hdl, base)) def test_windowProperties(self): diff --git a/unittests/test_wxdatetime.py b/unittests/test_wxdatetime.py index 4cd4beb6..ba693999 100644 --- a/unittests/test_wxdatetime.py +++ b/unittests/test_wxdatetime.py @@ -44,8 +44,12 @@ class datetime_Tests(wtc.WidgetTestCase): def test_datetimeGetAmPm(self): am, pm = wx.DateTime.GetAmPmStrings() - self.assertTrue(isinstance(am, basestring) and am != "") - self.assertTrue(isinstance(pm, basestring) and pm != "") + if wtc.isPython3(): + base = str + else: + base = unicode + self.assertTrue(isinstance(am, base) and am != "") + self.assertTrue(isinstance(pm, base) and pm != "") def test_datetimeProperties(self): diff --git a/unittests/wtc.py b/unittests/wtc.py index 65688ebd..9da83381 100644 --- a/unittests/wtc.py +++ b/unittests/wtc.py @@ -1,5 +1,6 @@ import imp_unittest, unittest import wx +import sys #--------------------------------------------------------------------------- @@ -66,6 +67,20 @@ class WidgetTestCase(unittest.TestCase): break intervals -= 1 + + +#--------------------------------------------------------------------------- + +def isPython3(): + return sys.version_info[0] >= 3 + + +def mybytes(text): + if isPython3(): + return bytes(text, 'utf-8') + else: + return str(text) + #---------------------------------------------------------------------------