From: <otm...@us...> - 2007-07-24 14:53:01
|
Revision: 3355 http://svn.sourceforge.net/jython/?rev=3355&view=rev Author: otmarhumbel Date: 2007-07-24 07:52:48 -0700 (Tue, 24 Jul 2007) Log Message: ----------- fix and bugtest for bug 1758838 (NullPointerException in execfile(), in interactive mode) Modified Paths: -------------- trunk/jython/src/org/python/core/PySystemState.java Added Paths: ----------- trunk/jython/bugtests/test401/ trunk/jython/bugtests/test401/to_be_executed.py trunk/jython/bugtests/test401.py Added: trunk/jython/bugtests/test401/to_be_executed.py =================================================================== --- trunk/jython/bugtests/test401/to_be_executed.py (rev 0) +++ trunk/jython/bugtests/test401/to_be_executed.py 2007-07-24 14:52:48 UTC (rev 3355) @@ -0,0 +1,4 @@ +# the contents of this file are not important for bug 1758838 + +class TestBug1758838: + pass Added: trunk/jython/bugtests/test401.py =================================================================== --- trunk/jython/bugtests/test401.py (rev 0) +++ trunk/jython/bugtests/test401.py 2007-07-24 14:52:48 UTC (rev 3355) @@ -0,0 +1,18 @@ +# +# Test for bug 1758838 +# +# execfile(<any file>) should not throw a NullPointerException +# +# The error only shows up in interactive interpretation (type "single" for the compilation). +# But we cannot use InteractiveInterpreter here since it catches all Exceptions, +# therefore we do the compilation 'by hand'. +# + +from org.python.core import Py +from org.python.core import PySystemState +from org.python.util import PythonInterpreter + +PySystemState.initialize() +interp = PythonInterpreter() +code = Py.compile_command_flags("execfile('test401/to_be_executed.py')", "<input>", "single", None, 1) +interp.exec(code) Modified: trunk/jython/src/org/python/core/PySystemState.java =================================================================== --- trunk/jython/src/org/python/core/PySystemState.java 2007-07-24 08:01:27 UTC (rev 3354) +++ trunk/jython/src/org/python/core/PySystemState.java 2007-07-24 14:52:48 UTC (rev 3355) @@ -801,11 +801,11 @@ // a reflected function is inserted in the class dict. static void displayhook(PyObject o) { - /* Print value except if None */ + /* Print value except if null or None */ /* After printing, also assign to '_' */ /* Before, set '_' to None to avoid recursion */ - if (o == Py.None) - return; + if (o == null || o == Py.None) + return; PySystemState sys = Py.getThreadState().systemState; sys.builtins.__setitem__("_", Py.None); This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <cg...@us...> - 2007-08-11 23:54:43
|
Revision: 3405 http://jython.svn.sourceforge.net/jython/?rev=3405&view=rev Author: cgroves Date: 2007-08-11 16:54:42 -0700 (Sat, 11 Aug 2007) Log Message: ----------- Moving all changes from branches/2.3 into trunk. Modified Paths: -------------- trunk/jython/Lib/javaos.py trunk/jython/Lib/jxxload_help/PackageManager.java trunk/jython/Lib/jxxload_help/PathVFSJavaLoader.java trunk/jython/Lib/marshal.py trunk/jython/Lib/re.py trunk/jython/Lib/test/javatests/AnonInner.java trunk/jython/Lib/test/javatests/ListTest.java trunk/jython/Lib/test/javatests/TestSupport.java trunk/jython/Lib/test/output/test_math trunk/jython/Lib/test/regrtest.py trunk/jython/Lib/test/test_datetime.py trunk/jython/Lib/test/test_descrtut.py trunk/jython/Lib/test/test_enumerate.py trunk/jython/Lib/test/test_generators.py trunk/jython/Lib/test/test_jy_internals.py trunk/jython/Lib/test/test_largefile.py trunk/jython/Lib/test/test_math.py trunk/jython/Lib/test/test_subclasses.py trunk/jython/Lib/test/test_support.py trunk/jython/NEWS trunk/jython/bugtests/classes/test119j.java trunk/jython/bugtests/classes/test202j.java trunk/jython/bugtests/driver.py trunk/jython/bugtests/test398.py trunk/jython/build.Lib.include.properties trunk/jython/build.xml trunk/jython/src/com/ziclix/python/sql/PyCursor.java trunk/jython/src/com/ziclix/python/sql/connect/Connectx.java trunk/jython/src/org/python/compiler/CodeCompiler.java trunk/jython/src/org/python/compiler/Module.java trunk/jython/src/org/python/core/AutoInternalTables.java trunk/jython/src/org/python/core/BytecodeLoader.java trunk/jython/src/org/python/core/CollectionIter.java trunk/jython/src/org/python/core/CollectionProxy.java trunk/jython/src/org/python/core/CompilerFlags.java trunk/jython/src/org/python/core/IdImpl.java trunk/jython/src/org/python/core/InternalTables.java trunk/jython/src/org/python/core/MergeState.java trunk/jython/src/org/python/core/Options.java trunk/jython/src/org/python/core/Py.java trunk/jython/src/org/python/core/PyArray.java trunk/jython/src/org/python/core/PyBeanProperty.java trunk/jython/src/org/python/core/PyCallIter.java trunk/jython/src/org/python/core/PyComplex.java trunk/jython/src/org/python/core/PyDictionary.java trunk/jython/src/org/python/core/PyException.java trunk/jython/src/org/python/core/PyFile.java trunk/jython/src/org/python/core/PyFloat.java trunk/jython/src/org/python/core/PyFrame.java trunk/jython/src/org/python/core/PyInstance.java trunk/jython/src/org/python/core/PyInteger.java trunk/jython/src/org/python/core/PyJavaClass.java trunk/jython/src/org/python/core/PyJavaInstance.java trunk/jython/src/org/python/core/PyJavaPackage.java trunk/jython/src/org/python/core/PyList.java trunk/jython/src/org/python/core/PyLong.java trunk/jython/src/org/python/core/PyMethodDescr.java trunk/jython/src/org/python/core/PyObject.java trunk/jython/src/org/python/core/PyObjectList.java trunk/jython/src/org/python/core/PyReflectedConstructor.java trunk/jython/src/org/python/core/PyReflectedFunction.java trunk/jython/src/org/python/core/PySequence.java trunk/jython/src/org/python/core/PyString.java trunk/jython/src/org/python/core/PyStringMap.java trunk/jython/src/org/python/core/PySystemState.java trunk/jython/src/org/python/core/PyTableCode.java trunk/jython/src/org/python/core/PyTuple.java trunk/jython/src/org/python/core/PyType.java trunk/jython/src/org/python/core/PyUnicode.java trunk/jython/src/org/python/core/SyspathJavaLoader.java trunk/jython/src/org/python/core/ThreadStateMapping.java trunk/jython/src/org/python/core/__builtin__.java trunk/jython/src/org/python/core/codecs.java trunk/jython/src/org/python/core/exceptions.java trunk/jython/src/org/python/modules/SHA1.java trunk/jython/src/org/python/modules/Setup.java trunk/jython/src/org/python/modules/_codecs.java trunk/jython/src/org/python/modules/_sre.java trunk/jython/src/org/python/modules/binascii.java trunk/jython/src/org/python/modules/cPickle.java trunk/jython/src/org/python/modules/cStringIO.java trunk/jython/src/org/python/modules/math.java trunk/jython/src/org/python/modules/md.java trunk/jython/src/org/python/modules/operator.java trunk/jython/src/org/python/modules/os.java trunk/jython/src/org/python/modules/sets/BaseSet.java trunk/jython/src/org/python/modules/sha.java trunk/jython/src/org/python/modules/sre/SRE_STATE.java trunk/jython/src/org/python/modules/struct.java trunk/jython/src/org/python/modules/time/Time.java trunk/jython/src/org/python/modules/types.java trunk/jython/src/org/python/modules/ucnhash.java trunk/jython/src/org/python/parser/PythonGrammarTokenManager.java trunk/jython/src/org/python/parser/PythonGrammarTreeConstants.java trunk/jython/src/org/python/parser/python.jjt trunk/jython/src/org/python/util/InteractiveConsole.java trunk/jython/src/org/python/util/JythoncAntTask.java trunk/jython/src/org/python/util/TemplateAntTask.java trunk/jython/src/org/python/util/jython.java trunk/jython/src/templates/README.txt trunk/jython/src/templates/bool.derived trunk/jython/src/templates/bool.expose trunk/jython/src/templates/complex.expose trunk/jython/src/templates/float.expose trunk/jython/src/templates/gexpose.py trunk/jython/src/templates/int.expose trunk/jython/src/templates/list.expose trunk/jython/src/templates/long.expose trunk/jython/src/templates/mappings trunk/jython/src/templates/object.expose trunk/jython/src/templates/str.expose trunk/jython/src/templates/tuple.expose trunk/jython/src/templates/type.expose Added Paths: ----------- trunk/jython/Lib/dis.py trunk/jython/Lib/doctest.py trunk/jython/Lib/opcode.py trunk/jython/Lib/readline.py trunk/jython/Lib/test/output/test_exceptions trunk/jython/Lib/test/pickletester.py trunk/jython/Lib/test/string_tests.py trunk/jython/Lib/test/test_bool.py trunk/jython/Lib/test/test_builtin.py trunk/jython/Lib/test/test_cmath.py trunk/jython/Lib/test/test_codecs.py trunk/jython/Lib/test/test_complex.py trunk/jython/Lib/test/test_format.py trunk/jython/Lib/test/test_isinstance.py trunk/jython/Lib/test/test_itertools.py trunk/jython/Lib/test/test_operator.py trunk/jython/Lib/test/test_popen.py trunk/jython/Lib/test/test_richcmp.py trunk/jython/Lib/test/test_socket_ssl.py trunk/jython/Lib/test/test_sort.py trunk/jython/Lib/test/test_str.py trunk/jython/Lib/test/test_sys.py trunk/jython/Lib/test/test_unicodedata.py trunk/jython/Lib/test/test_uu.py trunk/jython/src/org/python/core/PyBoolean.java trunk/jython/src/org/python/core/PyBooleanDerived.java trunk/jython/src/org/python/core/PyReversedIterator.java trunk/jython/src/org/python/core/packagecache/ trunk/jython/src/org/python/core/packagecache/CachedJarsPackageManager.java trunk/jython/src/org/python/core/packagecache/PackageManager.java trunk/jython/src/org/python/core/packagecache/PathPackageManager.java trunk/jython/src/org/python/core/packagecache/SysPackageManager.java trunk/jython/src/org/python/modules/cmath.java trunk/jython/src/org/python/modules/itertools.java trunk/jython/src/org/python/modules/random/ trunk/jython/src/org/python/modules/random/PyRandom.java trunk/jython/src/org/python/modules/random/PyRandomDerived.java trunk/jython/src/org/python/modules/random/RandomModule.java trunk/jython/src/templates/random.derived trunk/jython/src/templates/random.expose Removed Paths: ------------- trunk/jython/Lib/copy.py trunk/jython/Lib/getopt.py trunk/jython/Lib/inspect.py trunk/jython/Lib/pickle.py trunk/jython/Lib/test/output/test_unicode trunk/jython/Lib/test/test_inspect.py trunk/jython/Lib/test/test_unicode.py trunk/jython/bugtests/classes/test399j.java trunk/jython/bugtests/test399.py trunk/jython/src/org/python/core/BytecodeLoader1.java trunk/jython/src/org/python/core/BytecodeLoader2.java trunk/jython/src/org/python/core/CachedJarsPackageManager.java trunk/jython/src/org/python/core/CollectionIter2.java trunk/jython/src/org/python/core/CollectionProxy2.java trunk/jython/src/org/python/core/IdImpl1.java trunk/jython/src/org/python/core/IdImpl2.java trunk/jython/src/org/python/core/InternalTables1.java trunk/jython/src/org/python/core/InternalTables2.java trunk/jython/src/org/python/core/Java2Accessibility.java trunk/jython/src/org/python/core/JavaAccessibility.java trunk/jython/src/org/python/core/Loader.java trunk/jython/src/org/python/core/PackageManager.java trunk/jython/src/org/python/core/PathPackageManager.java trunk/jython/src/org/python/core/SysPackageManager.java trunk/jython/src/org/python/core/ThreadStateMapping2.java trunk/jython/src/org/python/rmi/ trunk/jython/src/templates/module.derived trunk/jython/src/templates/module.expose Property Changed: ---------------- trunk/jython/ Property changes on: trunk/jython ___________________________________________________________________ Name: svn:externals - CPythonLib http://svn.python.org/projects/python/branches/release22-maint/Lib/ + CPythonLib http://svn.python.org/projects/python/branches/release23-maint/Lib/ Deleted: trunk/jython/Lib/copy.py =================================================================== --- trunk/jython/Lib/copy.py 2007-08-11 23:52:18 UTC (rev 3404) +++ trunk/jython/Lib/copy.py 2007-08-11 23:54:42 UTC (rev 3405) @@ -1,330 +0,0 @@ -"""Generic (shallow and deep) copying operations. - -Interface summary: - - import copy - - x = copy.copy(y) # make a shallow copy of y - x = copy.deepcopy(y) # make a deep copy of y - -For module specific errors, copy.error is raised. - -The difference between shallow and deep copying is only relevant for -compound objects (objects that contain other objects, like lists or -class instances). - -- A shallow copy constructs a new compound object and then (to the - extent possible) inserts *the same objects* into in that the - original contains. - -- A deep copy constructs a new compound object and then, recursively, - inserts *copies* into it of the objects found in the original. - -Two problems often exist with deep copy operations that don't exist -with shallow copy operations: - - a) recursive objects (compound objects that, directly or indirectly, - contain a reference to themselves) may cause a recursive loop - - b) because deep copy copies *everything* it may copy too much, e.g. - administrative data structures that should be shared even between - copies - -Python's deep copy operation avoids these problems by: - - a) keeping a table of objects already copied during the current - copying pass - - b) letting user-defined classes override the copying operation or the - set of components copied - -This version does not copy types like module, class, function, method, -nor stack trace, stack frame, nor file, socket, window, nor array, nor -any similar types. - -Classes can use the same interfaces to control copying that they use -to control pickling: they can define methods called __getinitargs__(), -__getstate__() and __setstate__(). See the documentation for module -"pickle" for information on these methods. -""" - -# XXX need to support copy_reg here too... - -import types - -class Error(Exception): - pass -error = Error # backward compatibility - -try: - from org.python.core import PyStringMap -except ImportError: - PyStringMap = None - -__all__ = ["Error","error","copy","deepcopy"] - -def copy(x): - """Shallow copy operation on arbitrary Python objects. - - See the module's __doc__ string for more info. - """ - - try: - copierfunction = _copy_dispatch[type(x)] - except KeyError: - try: - copier = x.__copy__ - except AttributeError: - raise error, \ - "un(shallow)copyable object of type %s" % type(x) - y = copier() - else: - y = copierfunction(x) - return y - -_copy_dispatch = d = {} - -def _copy_atomic(x): - return x -d[types.NoneType] = _copy_atomic -d[types.IntType] = _copy_atomic -d[types.LongType] = _copy_atomic -d[types.FloatType] = _copy_atomic -d[types.StringType] = _copy_atomic -d[types.UnicodeType] = _copy_atomic -try: - d[types.CodeType] = _copy_atomic -except AttributeError: - pass -d[types.TypeType] = _copy_atomic -d[types.XRangeType] = _copy_atomic -d[types.ClassType] = _copy_atomic - -def _copy_list(x): - return x[:] -d[types.ListType] = _copy_list - -def _copy_tuple(x): - return x[:] -d[types.TupleType] = _copy_tuple - -def _copy_dict(x): - return x.copy() -d[types.DictionaryType] = _copy_dict -if PyStringMap is not None: - d[PyStringMap] = _copy_dict - -def _copy_inst(x): - if hasattr(x, '__copy__'): - return x.__copy__() - if hasattr(x, '__getinitargs__'): - args = x.__getinitargs__() - y = apply(x.__class__, args) - else: - if hasattr(x.__class__, '__del__'): - y = _EmptyClassDel() - else: - y = _EmptyClass() - y.__class__ = x.__class__ - if hasattr(x, '__getstate__'): - state = x.__getstate__() - else: - state = x.__dict__ - if hasattr(y, '__setstate__'): - y.__setstate__(state) - else: - y.__dict__.update(state) - return y -d[types.InstanceType] = _copy_inst - -del d - -def deepcopy(x, memo = None): - """Deep copy operation on arbitrary Python objects. - - See the module's __doc__ string for more info. - """ - - if memo is None: - memo = {} - d = id(x) - if memo.has_key(d): - return memo[d] - try: - copierfunction = _deepcopy_dispatch[type(x)] - except KeyError: - try: - copier = x.__deepcopy__ - except AttributeError: - raise error, \ - "un-deep-copyable object of type %s" % type(x) - y = copier(memo) - else: - y = copierfunction(x, memo) - memo[d] = y - return y - -_deepcopy_dispatch = d = {} - -def _deepcopy_atomic(x, memo): - return x -d[types.NoneType] = _deepcopy_atomic -d[types.IntType] = _deepcopy_atomic -d[types.LongType] = _deepcopy_atomic -d[types.FloatType] = _deepcopy_atomic -d[types.StringType] = _deepcopy_atomic -d[types.UnicodeType] = _deepcopy_atomic -d[types.CodeType] = _deepcopy_atomic -d[types.TypeType] = _deepcopy_atomic -d[types.XRangeType] = _deepcopy_atomic - -def _deepcopy_list(x, memo): - y = [] - memo[id(x)] = y - for a in x: - y.append(deepcopy(a, memo)) - return y -d[types.ListType] = _deepcopy_list - -def _deepcopy_tuple(x, memo): - y = [] - for a in x: - y.append(deepcopy(a, memo)) - d = id(x) - try: - return memo[d] - except KeyError: - pass - for i in range(len(x)): - if x[i] is not y[i]: - y = tuple(y) - break - else: - y = x - memo[d] = y - return y -d[types.TupleType] = _deepcopy_tuple - -def _deepcopy_dict(x, memo): - y = {} - memo[id(x)] = y - for key in x.keys(): - y[deepcopy(key, memo)] = deepcopy(x[key], memo) - return y -d[types.DictionaryType] = _deepcopy_dict -if PyStringMap is not None: - d[PyStringMap] = _deepcopy_dict - -def _keep_alive(x, memo): - """Keeps a reference to the object x in the memo. - - Because we remember objects by their id, we have - to assure that possibly temporary objects are kept - alive by referencing them. - We store a reference at the id of the memo, which should - normally not be used unless someone tries to deepcopy - the memo itself... - """ - try: - memo[id(memo)].append(x) - except KeyError: - # aha, this is the first one :-) - memo[id(memo)]=[x] - -def _deepcopy_inst(x, memo): - if hasattr(x, '__deepcopy__'): - return x.__deepcopy__(memo) - if hasattr(x, '__getinitargs__'): - args = x.__getinitargs__() - _keep_alive(args, memo) - args = deepcopy(args, memo) - y = apply(x.__class__, args) - else: - if hasattr(x.__class__, '__del__'): - y = _EmptyClassDel() - else: - y = _EmptyClass() - y.__class__ = x.__class__ - memo[id(x)] = y - if hasattr(x, '__getstate__'): - state = x.__getstate__() - _keep_alive(state, memo) - else: - state = x.__dict__ - state = deepcopy(state, memo) - if hasattr(y, '__setstate__'): - y.__setstate__(state) - else: - y.__dict__.update(state) - return y -d[types.InstanceType] = _deepcopy_inst - -del d - -del types - -# Helper for instance creation without calling __init__ -class _EmptyClass: - pass - -# Helper for instance creation without calling __init__. Used when -# the source class contains a __del__ attribute. -class _EmptyClassDel: - def __del__(self): - pass - -def _test(): - l = [None, 1, 2L, 3.14, 'xyzzy', (1, 2L), [3.14, 'abc'], - {'abc': 'ABC'}, (), [], {}] - l1 = copy(l) - print l1==l - l1 = map(copy, l) - print l1==l - l1 = deepcopy(l) - print l1==l - class C: - def __init__(self, arg=None): - self.a = 1 - self.arg = arg - if __name__ == '__main__': - import sys - file = sys.argv[0] - else: - file = __file__ - self.fp = open(file) - self.fp.close() - def __getstate__(self): - return {'a': self.a, 'arg': self.arg} - def __setstate__(self, state): - for key in state.keys(): - setattr(self, key, state[key]) - def __deepcopy__(self, memo = None): - new = self.__class__(deepcopy(self.arg, memo)) - new.a = self.a - return new - c = C('argument sketch') - l.append(c) - l2 = copy(l) - print l == l2 - print l - print l2 - l2 = deepcopy(l) - print l == l2 - print l - print l2 - l.append({l[1]: l, 'xyz': l[2]}) - l3 = copy(l) - import repr - print map(repr.repr, l) - print map(repr.repr, l1) - print map(repr.repr, l2) - print map(repr.repr, l3) - l3 = deepcopy(l) - import repr - print map(repr.repr, l) - print map(repr.repr, l1) - print map(repr.repr, l2) - print map(repr.repr, l3) - -if __name__ == '__main__': - _test() Added: trunk/jython/Lib/dis.py =================================================================== --- trunk/jython/Lib/dis.py (rev 0) +++ trunk/jython/Lib/dis.py 2007-08-11 23:54:42 UTC (rev 3405) @@ -0,0 +1 @@ +# stub dis module added to allow imports Added: trunk/jython/Lib/doctest.py =================================================================== --- trunk/jython/Lib/doctest.py (rev 0) +++ trunk/jython/Lib/doctest.py 2007-08-11 23:54:42 UTC (rev 3405) @@ -0,0 +1,1510 @@ +# Module doctest. +# Released to the public domain 16-Jan-2001, +# by Tim Peters (ti...@ho...). + +# Provided as-is; use at your own risk; no warranty; no promises; enjoy! + +"""Module doctest -- a framework for running examples in docstrings. + +NORMAL USAGE + +In normal use, end each module M with: + +def _test(): + import doctest, M # replace M with your module's name + return doctest.testmod(M) # ditto + +if __name__ == "__main__": + _test() + +Then running the module as a script will cause the examples in the +docstrings to get executed and verified: + +python M.py + +This won't display anything unless an example fails, in which case the +failing example(s) and the cause(s) of the failure(s) are printed to stdout +(why not stderr? because stderr is a lame hack <0.2 wink>), and the final +line of output is "Test failed.". + +Run it with the -v switch instead: + +python M.py -v + +and a detailed report of all examples tried is printed to stdout, along +with assorted summaries at the end. + +You can force verbose mode by passing "verbose=1" to testmod, or prohibit +it by passing "verbose=0". In either of those cases, sys.argv is not +examined by testmod. + +In any case, testmod returns a 2-tuple of ints (f, t), where f is the +number of docstring examples that failed and t is the total number of +docstring examples attempted. + + +WHICH DOCSTRINGS ARE EXAMINED? + ++ M.__doc__. + ++ f.__doc__ for all functions f in M.__dict__.values(), except those + defined in other modules. + ++ C.__doc__ for all classes C in M.__dict__.values(), except those + defined in other modules. + ++ If M.__test__ exists and "is true", it must be a dict, and + each entry maps a (string) name to a function object, class object, or + string. Function and class object docstrings found from M.__test__ + are searched even if the name is private, and strings are searched + directly as if they were docstrings. In output, a key K in M.__test__ + appears with name + <name of M>.__test__.K + +Any classes found are recursively searched similarly, to test docstrings in +their contained methods and nested classes. All names reached from +M.__test__ are searched. + +Optionally, functions with private names can be skipped (unless listed in +M.__test__) by supplying a function to the "isprivate" argument that will +identify private functions. For convenience, one such function is +supplied. docttest.is_private considers a name to be private if it begins +with an underscore (like "_my_func") but doesn't both begin and end with +(at least) two underscores (like "__init__"). By supplying this function +or your own "isprivate" function to testmod, the behavior can be customized. + +If you want to test docstrings in objects with private names too, stuff +them into an M.__test__ dict, or see ADVANCED USAGE below (e.g., pass your +own isprivate function to Tester's constructor, or call the rundoc method +of a Tester instance). + +WHAT'S THE EXECUTION CONTEXT? + +By default, each time testmod finds a docstring to test, it uses a *copy* +of M's globals (so that running tests on a module doesn't change the +module's real globals, and so that one test in M can't leave behind crumbs +that accidentally allow another test to work). This means examples can +freely use any names defined at top-level in M. It also means that sloppy +imports (see above) can cause examples in external docstrings to use +globals inappropriate for them. + +You can force use of your own dict as the execution context by passing +"globs=your_dict" to testmod instead. Presumably this would be a copy of +M.__dict__ merged with the globals from other imported modules. + + +WHAT IF I WANT TO TEST A WHOLE PACKAGE? + +Piece o' cake, provided the modules do their testing from docstrings. +Here's the test.py I use for the world's most elaborate Rational/ +floating-base-conversion pkg (which I'll distribute some day): + +from Rational import Cvt +from Rational import Format +from Rational import machprec +from Rational import Rat +from Rational import Round +from Rational import utils + +modules = (Cvt, + Format, + machprec, + Rat, + Round, + utils) + +def _test(): + import doctest + import sys + verbose = "-v" in sys.argv + for mod in modules: + doctest.testmod(mod, verbose=verbose, report=0) + doctest.master.summarize() + +if __name__ == "__main__": + _test() + +IOW, it just runs testmod on all the pkg modules. testmod remembers the +names and outcomes (# of failures, # of tries) for each item it's seen, and +passing "report=0" prevents it from printing a summary in verbose mode. +Instead, the summary is delayed until all modules have been tested, and +then "doctest.master.summarize()" forces the summary at the end. + +So this is very nice in practice: each module can be tested individually +with almost no work beyond writing up docstring examples, and collections +of modules can be tested too as a unit with no more work than the above. + + +WHAT ABOUT EXCEPTIONS? + +No problem, as long as the only output generated by the example is the +traceback itself. For example: + + >>> [1, 2, 3].remove(42) + Traceback (most recent call last): + File "<stdin>", line 1, in ? + ValueError: list.remove(x): x not in list + >>> + +Note that only the exception type and value are compared (specifically, +only the last line in the traceback). + + +ADVANCED USAGE + +doctest.testmod() captures the testing policy I find most useful most +often. You may want other policies. + +testmod() actually creates a local instance of class doctest.Tester, runs +appropriate methods of that class, and merges the results into global +Tester instance doctest.master. + +You can create your own instances of doctest.Tester, and so build your own +policies, or even run methods of doctest.master directly. See +doctest.Tester.__doc__ for details. + + +SO WHAT DOES A DOCSTRING EXAMPLE LOOK LIKE ALREADY!? + +Oh ya. It's easy! In most cases a copy-and-paste of an interactive +console session works fine -- just make sure the leading whitespace is +rigidly consistent (you can mix tabs and spaces if you're too lazy to do it +right, but doctest is not in the business of guessing what you think a tab +means). + + >>> # comments are ignored + >>> x = 12 + >>> x + 12 + >>> if x == 13: + ... print "yes" + ... else: + ... print "no" + ... print "NO" + ... print "NO!!!" + ... + no + NO + NO!!! + >>> + +Any expected output must immediately follow the final ">>>" or "..." line +containing the code, and the expected output (if any) extends to the next +">>>" or all-whitespace line. That's it. + +Bummers: + ++ Expected output cannot contain an all-whitespace line, since such a line + is taken to signal the end of expected output. + ++ Output to stdout is captured, but not output to stderr (exception + tracebacks are captured via a different means). + ++ If you continue a line via backslashing in an interactive session, or for + any other reason use a backslash, you need to double the backslash in the + docstring version. This is simply because you're in a string, and so the + backslash must be escaped for it to survive intact. Like: + +>>> if "yes" == \\ +... "y" + \\ +... "es": # in the source code you'll see the doubled backslashes +... print 'yes' +yes + +The starting column doesn't matter: + +>>> assert "Easy!" + >>> import math + >>> math.floor(1.9) + 1.0 + +and as many leading whitespace characters are stripped from the expected +output as appeared in the initial ">>>" line that triggered it. + +If you execute this very file, the examples above will be found and +executed, leading to this output in verbose mode: + +Running doctest.__doc__ +Trying: [1, 2, 3].remove(42) +Expecting: +Traceback (most recent call last): + File "<stdin>", line 1, in ? +ValueError: list.remove(x): x not in list +ok +Trying: x = 12 +Expecting: nothing +ok +Trying: x +Expecting: 12 +ok +Trying: +if x == 13: + print "yes" +else: + print "no" + print "NO" + print "NO!!!" +Expecting: +no +NO +NO!!! +ok +... and a bunch more like that, with this summary at the end: + +5 items had no tests: + doctest.Tester.__init__ + doctest.Tester.run__test__ + doctest.Tester.summarize + doctest.run_docstring_examples + doctest.testmod +12 items passed all tests: + 8 tests in doctest + 6 tests in doctest.Tester + 10 tests in doctest.Tester.merge + 14 tests in doctest.Tester.rundict + 3 tests in doctest.Tester.rundoc + 3 tests in doctest.Tester.runstring + 2 tests in doctest.__test__._TestClass + 2 tests in doctest.__test__._TestClass.__init__ + 2 tests in doctest.__test__._TestClass.get + 1 tests in doctest.__test__._TestClass.square + 2 tests in doctest.__test__.string + 7 tests in doctest.is_private +60 tests in 17 items. +60 passed and 0 failed. +Test passed. +""" + +__all__ = [ + 'testmod', + 'run_docstring_examples', + 'is_private', + 'Tester', + 'DocTestTestFailure', + 'DocTestSuite', + 'testsource', + 'debug', + 'master', +] + +import __future__ + +import re +PS1 = ">>>" +PS2 = "..." +_isPS1 = re.compile(r"(\s*)" + re.escape(PS1)).match +_isPS2 = re.compile(r"(\s*)" + re.escape(PS2)).match +_isEmpty = re.compile(r"\s*$").match +_isComment = re.compile(r"\s*#").match +del re + +from types import StringTypes as _StringTypes + +from inspect import isclass as _isclass +from inspect import isfunction as _isfunction +from inspect import ismethod as _ismethod +from inspect import ismodule as _ismodule +from inspect import classify_class_attrs as _classify_class_attrs + +# Option constants. +DONT_ACCEPT_TRUE_FOR_1 = 1 << 0 + +# Extract interactive examples from a string. Return a list of triples, +# (source, outcome, lineno). "source" is the source code, and ends +# with a newline iff the source spans more than one line. "outcome" is +# the expected output if any, else an empty string. When not empty, +# outcome always ends with a newline. "lineno" is the line number, +# 0-based wrt the start of the string, of the first source line. + +def _extract_examples(s): + isPS1, isPS2 = _isPS1, _isPS2 + isEmpty, isComment = _isEmpty, _isComment + examples = [] + lines = s.split("\n") + i, n = 0, len(lines) + while i < n: + line = lines[i] + i = i + 1 + m = isPS1(line) + if m is None: + continue + j = m.end(0) # beyond the prompt + if isEmpty(line, j) or isComment(line, j): + # a bare prompt or comment -- not interesting + continue + lineno = i - 1 + if line[j] != " ": + raise ValueError("line " + `lineno` + " of docstring lacks " + "blank after " + PS1 + ": " + line) + j = j + 1 + blanks = m.group(1) + nblanks = len(blanks) + # suck up this and following PS2 lines + source = [] + while 1: + source.append(line[j:]) + line = lines[i] + m = isPS2(line) + if m: + if m.group(1) != blanks: + raise ValueError("inconsistent leading whitespace " + "in line " + `i` + " of docstring: " + line) + i = i + 1 + else: + break + if len(source) == 1: + source = source[0] + else: + # get rid of useless null line from trailing empty "..." + if source[-1] == "": + del source[-1] + source = "\n".join(source) + "\n" + # suck up response + if isPS1(line) or isEmpty(line): + expect = "" + else: + expect = [] + while 1: + if line[:nblanks] != blanks: + raise ValueError("inconsistent leading whitespace " + "in line " + `i` + " of docstring: " + line) + expect.append(line[nblanks:]) + i = i + 1 + line = lines[i] + if isPS1(line) or isEmpty(line): + break + expect = "\n".join(expect) + "\n" + examples.append( (source, expect, lineno) ) + return examples + +# Capture stdout when running examples. + +class _SpoofOut: + def __init__(self): + self.clear() + def write(self, s): + self.buf.append(s) + def get(self): + guts = "".join(self.buf) + # If anything at all was written, make sure there's a trailing + # newline. There's no way for the expected output to indicate + # that a trailing newline is missing. + if guts and not guts.endswith("\n"): + guts = guts + "\n" + # Prevent softspace from screwing up the next test case, in + # case they used print with a trailing comma in an example. + if hasattr(self, "softspace"): + del self.softspace + return guts + def clear(self): + self.buf = [] + if hasattr(self, "softspace"): + del self.softspace + def flush(self): + # JPython calls flush + pass + +# Display some tag-and-msg pairs nicely, keeping the tag and its msg +# on the same line when that makes sense. + +def _tag_out(printer, *tag_msg_pairs): + for tag, msg in tag_msg_pairs: + printer(tag + ":") + msg_has_nl = msg[-1:] == "\n" + msg_has_two_nl = msg_has_nl and \ + msg.find("\n") < len(msg) - 1 + if len(tag) + len(msg) < 76 and not msg_has_two_nl: + printer(" ") + else: + printer("\n") + printer(msg) + if not msg_has_nl: + printer("\n") + +# Run list of examples, in context globs. "out" can be used to display +# stuff to "the real" stdout, and fakeout is an instance of _SpoofOut +# that captures the examples' std output. Return (#failures, #tries). + +def _run_examples_inner(out, fakeout, examples, globs, verbose, name, + compileflags, optionflags): + import sys, traceback + OK, BOOM, FAIL = range(3) + NADA = "nothing" + stderr = _SpoofOut() + failures = 0 + for source, want, lineno in examples: + if verbose: + _tag_out(out, ("Trying", source), + ("Expecting", want or NADA)) + fakeout.clear() + try: + exec compile(source, "<string>", "single", + compileflags, 1) in globs + got = fakeout.get() + state = OK + except KeyboardInterrupt: + raise + except: + # See whether the exception was expected. + if want.find("Traceback (innermost last):\n") == 0 or \ + want.find("Traceback (most recent call last):\n") == 0: + # Only compare exception type and value - the rest of + # the traceback isn't necessary. + want = want.split('\n')[-2] + '\n' + exc_type, exc_val = sys.exc_info()[:2] + got = traceback.format_exception_only(exc_type, exc_val)[-1] + state = OK + else: + # unexpected exception + stderr.clear() + traceback.print_exc(file=stderr) + state = BOOM + + if state == OK: + if (got == want or + (not (optionflags & DONT_ACCEPT_TRUE_FOR_1) and + (got, want) in (("True\n", "1\n"), ("False\n", "0\n")) + ) + ): + if verbose: + out("ok\n") + continue + state = FAIL + + assert state in (FAIL, BOOM) + failures = failures + 1 + out("*" * 65 + "\n") + _tag_out(out, ("Failure in example", source)) + out("from line #" + `lineno` + " of " + name + "\n") + if state == FAIL: + _tag_out(out, ("Expected", want or NADA), ("Got", got)) + else: + assert state == BOOM + _tag_out(out, ("Exception raised", stderr.get())) + + return failures, len(examples) + +# Get the future-flags associated with the future features that have been +# imported into globs. + +def _extract_future_flags(globs): + flags = 0 + for fname in __future__.all_feature_names: + feature = globs.get(fname, None) + if feature is getattr(__future__, fname): + flags |= feature.compiler_flag + return flags + +# Run list of examples, in a shallow copy of context (dict) globs. +# Return (#failures, #tries). + +def _run_examples(examples, globs, verbose, name, compileflags, + optionflags): + import sys + saveout = sys.stdout + globs = globs.copy() + try: + sys.stdout = fakeout = _SpoofOut() + x = _run_examples_inner(saveout.write, fakeout, examples, + globs, verbose, name, compileflags, + optionflags) + finally: + sys.stdout = saveout + # While Python gc can clean up most cycles on its own, it doesn't + # chase frame objects. This is especially irksome when running + # generator tests that raise exceptions, because a named generator- + # iterator gets an entry in globs, and the generator-iterator + # object's frame's traceback info points back to globs. This is + # easy to break just by clearing the namespace. This can also + # help to break other kinds of cycles, and even for cycles that + # gc can break itself it's better to break them ASAP. + globs.clear() + return x + +def run_docstring_examples(f, globs, verbose=0, name="NoName", + compileflags=None, optionflags=0): + """f, globs, verbose=0, name="NoName" -> run examples from f.__doc__. + + Use (a shallow copy of) dict globs as the globals for execution. + Return (#failures, #tries). + + If optional arg verbose is true, print stuff even if there are no + failures. + Use string name in failure msgs. + """ + + try: + doc = f.__doc__ + if not doc: + # docstring empty or None + return 0, 0 + # just in case CT invents a doc object that has to be forced + # to look like a string <0.9 wink> + doc = str(doc) + except KeyboardInterrupt: + raise + except: + return 0, 0 + + e = _extract_examples(doc) + if not e: + return 0, 0 + if compileflags is None: + compileflags = _extract_future_flags(globs) + return _run_examples(e, globs, verbose, name, compileflags, optionflags) + +def is_private(prefix, base): + """prefix, base -> true iff name prefix + "." + base is "private". + + Prefix may be an empty string, and base does not contain a period. + Prefix is ignored (although functions you write conforming to this + protocol may make use of it). + Return true iff base begins with an (at least one) underscore, but + does not both begin and end with (at least) two underscores. + >>> is_private("a.b", "my_func") + False + >>> is_private("____", "_my_func") + True + >>> is_private("someclass", "__init__") + False + >>> is_private("sometypo", "__init_") + True + >>> is_private("x.y.z", "_") + True + >>> is_private("_x.y.z", "__") + False + >>> is_private("", "") # senseless but consistent + False + """ + + return base[:1] == "_" and not base[:2] == "__" == base[-2:] + +# Determine if a class of function was defined in the given module. + +def _from_module(module, object): + if _isfunction(object): + return module.__dict__ is object.func_globals + if _isclass(object): + # Jython transition 2.3 + # Java classes appear as Python classes to inspect, but they have no + # __module__ http://jython.org/bugs/1758279 + # org.python.modules uses Java classes to masq + if not hasattr(object, '__module__'): + return False + return module.__name__ == object.__module__ + raise ValueError("object must be a class or function") + +class Tester: + """Class Tester -- runs docstring examples and accumulates stats. + +In normal use, function doctest.testmod() hides all this from you, +so use that if you can. Create your own instances of Tester to do +fancier things. + +Methods: + runstring(s, name) + Search string s for examples to run; use name for logging. + Return (#failures, #tries). + + rundoc(object, name=None) + Search object.__doc__ for examples to run; use name (or + object.__name__) for logging. Return (#failures, #tries). + + rundict(d, name, module=None) + Search for examples in docstrings in all of d.values(); use name + for logging. Exclude functions and classes not defined in module + if specified. Return (#failures, #tries). + + run__test__(d, name) + Treat dict d like module.__test__. Return (#failures, #tries). + + summarize(verbose=None) + Display summary of testing results, to stdout. Return + (#failures, #tries). + + merge(other) + Merge in the test results from Tester instance "other". + +>>> from doctest import Tester +>>> t = Tester(globs={'x': 42}, verbose=0) +>>> t.runstring(r''' +... >>> x = x * 2 +... >>> print x +... 42 +... ''', 'XYZ') +***************************************************************** +Failure in example: print x +from line #2 of XYZ +Expected: 42 +Got: 84 +(1, 2) +>>> t.runstring(">>> x = x * 2\\n>>> print x\\n84\\n", 'example2') +(0, 2) +>>> t.summarize() +***************************************************************** +1 items had failures: + 1 of 2 in XYZ +***Test Failed*** 1 failures. +(1, 4) +>>> t.summarize(verbose=1) +1 items passed all tests: + 2 tests in example2 +***************************************************************** +1 items had failures: + 1 of 2 in XYZ +4 tests in 2 items. +3 passed and 1 failed. +***Test Failed*** 1 failures. +(1, 4) +>>> +""" + + def __init__(self, mod=None, globs=None, verbose=None, + isprivate=None, optionflags=0): + """mod=None, globs=None, verbose=None, isprivate=None, +optionflags=0 + +See doctest.__doc__ for an overview. + +Optional keyword arg "mod" is a module, whose globals are used for +executing examples. If not specified, globs must be specified. + +Optional keyword arg "globs" gives a dict to be used as the globals +when executing examples; if not specified, use the globals from +module mod. + +In either case, a copy of the dict is used for each docstring +examined. + +Optional keyword arg "verbose" prints lots of stuff if true, only +failures if false; by default, it's true iff "-v" is in sys.argv. + +Optional keyword arg "isprivate" specifies a function used to determine +whether a name is private. The default function is to assume that +no functions are private. The "isprivate" arg may be set to +doctest.is_private in order to skip over functions marked as private +using an underscore naming convention; see its docs for details. + +See doctest.testmod docs for the meaning of optionflags. +""" + + if mod is None and globs is None: + raise TypeError("Tester.__init__: must specify mod or globs") + if mod is not None and not _ismodule(mod): + raise TypeError("Tester.__init__: mod must be a module; " + + `mod`) + if globs is None: + globs = mod.__dict__ + self.globs = globs + + if verbose is None: + import sys + verbose = "-v" in sys.argv + self.verbose = verbose + + # By default, assume that nothing is private + if isprivate is None: + isprivate = lambda prefix, base: 0 + self.isprivate = isprivate + + self.optionflags = optionflags + + self.name2ft = {} # map name to (#failures, #trials) pair + + self.compileflags = _extract_future_flags(globs) + + def runstring(self, s, name): + """ + s, name -> search string s for examples to run, logging as name. + + Use string name as the key for logging the outcome. + Return (#failures, #examples). + + >>> t = Tester(globs={}, verbose=1) + >>> test = r''' + ... # just an example + ... >>> x = 1 + 2 + ... >>> x + ... 3 + ... ''' + >>> t.runstring(test, "Example") + Running string Example + Trying: x = 1 + 2 + Expecting: nothing + ok + Trying: x + Expecting: 3 + ok + 0 of 2 examples failed in string Example + (0, 2) + """ + + if self.verbose: + print "Running string", name + f = t = 0 + e = _extract_examples(s) + if e: + f, t = _run_examples(e, self.globs, self.verbose, name, + self.compileflags, self.optionflags) + if self.verbose: + print f, "of", t, "examples failed in string", name + self.__record_outcome(name, f, t) + return f, t + + def rundoc(self, object, name=None): + """ + object, name=None -> search object.__doc__ for examples to run. + + Use optional string name as the key for logging the outcome; + by default use object.__name__. + Return (#failures, #examples). + If object is a class object, search recursively for method + docstrings too. + object.__doc__ is examined regardless of name, but if object is + a class, whether private names reached from object are searched + depends on the constructor's "isprivate" argument. + + >>> t = Tester(globs={}, verbose=0) + >>> def _f(): + ... '''Trivial docstring example. + ... >>> assert 2 == 2 + ... ''' + ... return 32 + ... + >>> t.rundoc(_f) # expect 0 failures in 1 example + (0, 1) + """ + + if name is None: + try: + name = object.__name__ + except AttributeError: + raise ValueError("Tester.rundoc: name must be given " + "when object.__name__ doesn't exist; " + `object`) + if self.verbose: + print "Running", name + ".__doc__" + f, t = run_docstring_examples(object, self.globs, self.verbose, name, + self.compileflags, self.optionflags) + if self.verbose: + print f, "of", t, "examples failed in", name + ".__doc__" + self.__record_outcome(name, f, t) + if _isclass(object): + # In 2.2, class and static methods complicate life. Build + # a dict "that works", by hook or by crook. + d = {} + for tag, kind, homecls, value in _classify_class_attrs(object): + + if homecls is not object: + # Only look at names defined immediately by the class. + continue + + elif self.isprivate(name, tag): + continue + + elif kind == "method": + # value is already a function + d[tag] = value + + elif kind == "static method": + # value isn't a function, but getattr reveals one + d[tag] = getattr(object, tag) + + elif kind == "class method": + # Hmm. A classmethod object doesn't seem to reveal + # enough. But getattr turns it into a bound method, + # and from there .im_func retrieves the underlying + # function. + d[tag] = getattr(object, tag).im_func + + elif kind == "property": + # The methods implementing the property have their + # own docstrings -- but the property may have one too. + if value.__doc__ is not None: + d[tag] = str(value.__doc__) + + elif kind == "data": + # Grab nested classes. + if _isclass(value): + d[tag] = value + + else: + raise ValueError("teach doctest about %r" % kind) + + f2, t2 = self.run__test__(d, name) + f += f2 + t += t2 + + return f, t + + def rundict(self, d, name, module=None): + """ + d, name, module=None -> search for docstring examples in d.values(). + + For k, v in d.items() such that v is a function or class, + do self.rundoc(v, name + "." + k). Whether this includes + objects with private names depends on the constructor's + "isprivate" argument. If module is specified, functions and + classes that are not defined in module are excluded. + Return aggregate (#failures, #examples). + + Build and populate two modules with sample functions to test that + exclusion of external functions and classes works. + + >>> import new + >>> m1 = new.module('_m1') + >>> m2 = new.module('_m2') + >>> test_data = \""" + ... def _f(): + ... '''>>> assert 1 == 1 + ... ''' + ... def g(): + ... '''>>> assert 2 != 1 + ... ''' + ... class H: + ... '''>>> assert 2 > 1 + ... ''' + ... def bar(self): + ... '''>>> assert 1 < 2 + ... ''' + ... \""" + >>> exec test_data in m1.__dict__ + >>> exec test_data in m2.__dict__ + >>> m1.__dict__.update({"f2": m2._f, "g2": m2.g, "h2": m2.H}) + + Tests that objects outside m1 are excluded: + + >>> t = Tester(globs={}, verbose=0, isprivate=is_private) + >>> t.rundict(m1.__dict__, "rundict_test", m1) # _f, f2 and g2 and h2 skipped + (0, 3) + + Again, but with the default isprivate function allowing _f: + + >>> t = Tester(globs={}, verbose=0) + >>> t.rundict(m1.__dict__, "rundict_test_pvt", m1) # Only f2, g2 and h2 skipped + (0, 4) + + And once more, not excluding stuff outside m1: + + >>> t = Tester(globs={}, verbose=0) + >>> t.rundict(m1.__dict__, "rundict_test_pvt") # None are skipped. + (0, 8) + + The exclusion of objects from outside the designated module is + meant to be invoked automagically by testmod. + + >>> testmod(m1, isprivate=is_private) + (0, 3) + + """ + + if not hasattr(d, "items"): + raise TypeError("Tester.rundict: d must support .items(); " + + `d`) + f = t = 0 + # Run the tests by alpha order of names, for consistency in + # verbose-mode output. + names = d.keys() + names.sort() + for thisname in names: + value = d[thisname] + if _isfunction(value) or _isclass(value): + if module and not _from_module(module, value): + continue + f2, t2 = self.__runone(value, name + "." + thisname) + f = f + f2 + t = t + t2 + return f, t + + def run__test__(self, d, name): + """d, name -> Treat dict d like module.__test__. + + Return (#failures, #tries). + See testmod.__doc__ for details. + """ + + failures = tries = 0 + prefix = name + "." + savepvt = self.isprivate + try: + self.isprivate = lambda *args: 0 + # Run the tests by alpha order of names, for consistency in + # verbose-mode output. + keys = d.keys() + keys.sort() + for k in keys: + v = d[k] + thisname = prefix + k + if type(v) in _StringTypes: + f, t = self.runstring(v, thisname) + elif _isfunction(v) or _isclass(v) or _ismethod(v): + f, t = self.rundoc(v, thisname) + else: + raise TypeError("Tester.run__test__: values in " + "dict must be strings, functions, methods, " + "or classes; " + `v`) + failures = failures + f + tries = tries + t + finally: + self.isprivate = savepvt + return failures, tries + + def summarize(self, verbose=None): + """ + verbose=None -> summarize results, return (#failures, #tests). + + Print summary of test results to stdout. + Optional arg 'verbose' controls how wordy this is. By + default, use the verbose setting established by the + constructor. + """ + + if verbose is None: + verbose = self.verbose + notests = [] + passed = [] + failed = [] + totalt = totalf = 0 + for x in self.name2ft.items(): + name, (f, t) = x + assert f <= t + totalt = totalt + t + totalf = totalf + f + if t == 0: + notests.append(name) + elif f == 0: + passed.append( (name, t) ) + else: + failed.append(x) + if verbose: + if notests: + print len(notests), "items had no tests:" + notests.sort() + for thing in notests: + print " ", thing + if passed: + print len(passed), "items passed all tests:" + passed.sort() + for thing, count in passed: + print " %3d tests in %s" % (count, thing) + if failed: + print "*" * 65 + print len(failed), "items had failures:" + failed.sort() + for thing, (f, t) in failed: + print " %3d of %3d in %s" % (f, t, thing) + if verbose: + print totalt, "tests in", len(self.name2ft), "items." + print totalt - totalf, "passed and", totalf, "failed." + if totalf: + print "***Test Failed***", totalf, "failures." + elif verbose: + print "Test passed." + return totalf, totalt + + def merge(self, other): + """ + other -> merge in test results from the other Tester instance. + + If self and other both have a test result for something + with the same name, the (#failures, #tests) results are + summed, and a warning is printed to stdout. + + >>> from doctest import Tester + >>> t1 = Tester(globs={}, verbose=0) + >>> t1.runstring(''' + ... >>> x = 12 + ... >>> print x + ... 12 + ... ''', "t1example") + (0, 2) + >>> + >>> t2 = Tester(globs={}, verbose=0) + >>> t2.runstring(''' + ... >>> x = 13 + ... >>> print x + ... 13 + ... ''', "t2example") + (0, 2) + >>> common = ">>> assert 1 + 2 == 3\\n" + >>> t1.runstring(common, "common") + (0, 1) + >>> t2.runstring(common, "common") + (0, 1) + >>> t1.merge(t2) + *** Tester.merge: 'common' in both testers; summing outcomes. + >>> t1.summarize(1) + 3 items passed all tests: + 2 tests in common + 2 tests in t1example + 2 tests in t2example + 6 tests in 3 items. + 6 passed and 0 failed. + Test passed. + (0, 6) + >>> + """ + + d = self.name2ft + for name, (f, t) in other.name2ft.items(): + if name in d: + print "*** Tester.merge: '" + name + "' in both" \ + " testers; summing outcomes." + f2, t2 = d[name] + f = f + f2 + t = t + t2 + d[name] = f, t + + def __record_outcome(self, name, f, t): + if name in self.name2ft: + print "*** Warning: '" + name + "' was tested before;", \ + "summing outcomes." + f2, t2 = self.name2ft[name] + f = f + f2 + t = t + t2 + self.name2ft[name] = f, t + + def __runone(self, target, name): + if "." in name: + i = name.rindex(".") + prefix, base = name[:i], name[i+1:] + else: + prefix, base = "", base + if self.isprivate(prefix, base): + return 0, 0 + return self.rundoc(target, name) + +master = None + +def testmod(m=None, name=None, globs=None, verbose=None, isprivate=None, + report=True, optionflags=0): + """m=None, name=None, globs=None, verbose=None, isprivate=None, + report=True, optionflags=0 + + Test examples in docstrings in functions and classes reachable + from module m (or the current module if m is not supplied), starting + with m.__doc__. Unless isprivate is specified, private names + are not skipped. + + Also test examples reachable from dict m.__test__ if it exists and is + not None. m.__dict__ maps names to functions, classes and strings; + function and class docstrings are tested even if the name is private; + strings are tested directly, as if they were docstrings. + + Return (#failures, #tests). + + See doctest.__doc__ for an overview. + + Optional keyword arg "name" gives the name of the module; by default + use m.__name__. + + Optional keyword arg "globs" gives a dict to be used as the globals + when executing examples; by default, use m.__dict__. A copy of this + dict is actually used for each docstring, so that each docstring's + examples start with a clean slate. + + Optional keyword arg "verbose" prints lots of stuff if true, prints + only failures if false; by default, it's true iff "-v" is in sys.argv. + + Optional keyword arg "isprivate" specifies a function used to + determine whether a name is private. The default function is + treat all functions as public. Optionally, "isprivate" can be + set to doctest.is_private to skip over functions marked as private + using the underscore naming convention; see its docs for details. + + Optional keyword arg "report" prints a summary at the end when true, + else prints nothing at the end. In verbose mode, the summary is + detailed, else very brief (in fact, empty if all tests passed). + + Optional keyword arg "optionflags" or's together module constants, + and defaults to 0. This is new in 2.3. Possible values: + + DONT_ACCEPT_TRUE_FOR_1 + By default, if an expected output block contains just "1", + an actual output block containing just "True" is considered + to be a match, and similarly for "0" versus "False". When + DONT_ACCEPT_TRUE_FOR_1 is specified, neither substitution + is allowed. + + Advanced tomfoolery: testmod runs methods of a local instance of + class doctest.Tester, then merges the results into (or creates) + global Tester instance doctest.master. Methods of doctest.master + can be called directly too, if you want to do something unusual. + Passing report=0 to testmod is especially useful then, to delay + displaying a summary. Invoke doctest.master.summarize(verbose) + when you're done fiddling. + """ + + global master + + if m is None: + import sys + # DWA - m will still be None if this wasn't invoked from the command + # line, in which case the following TypeError is about as good an error + # as we should expect + m = sys.modules.get('__main__') + + if not _ismodule(m): + raise TypeError("testmod: module required; " + `m`) + if name is None: + name = m.__name__ + tester = Tester(m, globs=globs, verbose=verbose, isprivate=isprivate, + optionflags=optionflags) + failures, tries = tester.rundoc(m, name) + f, t = tester.rundict(m.__dict__, name, m) + failures += f + tries += t + if hasattr(m, "__test__"): + testdict = m.__test__ + if testdict: + if not hasattr(testdict, "items"): + raise TypeError("testmod: module.__test__ must support " + ".items(); " + `testdict`) + f, t = tester.run__test__(testdict, name + ".__test__") + failures += f + tries += t + if report: + tester.summarize() + if master is None: + master = tester + else: + master.merge(tester) + return failures, tries + +########################################################################### +# Various doctest extensions, to make using doctest with unittest +# easier, and to help debugging when a doctest goes wrong. Original +# code by Jim Fulton. + +# Utilities. + +# If module is None, return the calling module (the module that called +# the routine that called _normalize_module -- this normally won't be +# doctest!). If ... [truncated message content] |
From: <cg...@us...> - 2007-08-12 06:15:09
|
Revision: 3409 http://jython.svn.sourceforge.net/jython/?rev=3409&view=rev Author: cgroves Date: 2007-08-11 23:15:07 -0700 (Sat, 11 Aug 2007) Log Message: ----------- Applying patch #1770407 from yole to fix bug #1758317, bool objects fail to pickle Modified Paths: -------------- trunk/jython/Lib/test/test_bool.py trunk/jython/src/org/python/modules/cPickle.java Modified: trunk/jython/Lib/test/test_bool.py =================================================================== --- trunk/jython/Lib/test/test_bool.py 2007-08-12 05:57:22 UTC (rev 3408) +++ trunk/jython/Lib/test/test_bool.py 2007-08-12 06:15:07 UTC (rev 3409) @@ -341,11 +341,6 @@ check(Baz()) # Jython transition 2.3 -# pickle doesn't work on bool -# http://jython.org/bugs/1758317 -del BoolTest.test_picklevalues -del BoolTest.test_mixedpickle -del BoolTest.test_cpickle #operator missing is function # http://jython.org/bugs/1758315 del BoolTest.test_operator Modified: trunk/jython/src/org/python/modules/cPickle.java =================================================================== --- trunk/jython/src/org/python/modules/cPickle.java 2007-08-12 05:57:22 UTC (rev 3408) +++ trunk/jython/src/org/python/modules/cPickle.java 2007-08-12 06:15:07 UTC (rev 3409) @@ -439,6 +439,8 @@ PyType.fromClass(PyTuple.class); private static PyType FileType = PyType.fromClass(PyFile.class); + private static PyType BoolType = + PyType.fromClass(PyBoolean.class); private static PyObject dict; @@ -1030,6 +1032,8 @@ save_global(object); else if (type == BuiltinFunctionType) save_global(object); + else if (type == BoolType) + save_bool(object); else return false; return true; @@ -1072,7 +1076,14 @@ } } + private void save_bool(PyObject object) { + int value = ((PyBoolean) object).getValue(); + file.write(INT); + file.write(value != 0 ? "01" : "00"); + file.write("\n"); + } + final private void save_long(PyObject object) { file.write(LONG); file.write(object.toString()); @@ -1654,13 +1665,21 @@ PyObject value; // The following could be abstracted into a common string // -> int/long method. - try { - value = Py.newInteger(Integer.parseInt(line)); - } catch(NumberFormatException e) { + if (line.equals("01")) { + value = Py.newBoolean(true); + } + else if (line.equals("00")) { + value = Py.newBoolean(false); + } + else { try { - value = Py.newLong(line); - } catch(NumberFormatException e2) { - throw Py.ValueError("could not convert string to int"); + value = Py.newInteger(Integer.parseInt(line)); + } catch(NumberFormatException e) { + try { + value = Py.newLong(line); + } catch(NumberFormatException e2) { + throw Py.ValueError("could not convert string to int"); + } } } push(value); This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <cg...@us...> - 2007-08-12 22:01:27
|
Revision: 3412 http://jython.svn.sourceforge.net/jython/?rev=3412&view=rev Author: cgroves Date: 2007-08-12 15:01:25 -0700 (Sun, 12 Aug 2007) Log Message: ----------- Applying patch #1772134 from yole to fix bug #1758312. Several bits of unpickling code expect decoding with the string-escape codec to return a str object as explained on http://www.python.org/doc/2.3.5/lib/node130.html. However, decode always returned PyUnicode up until now, so checks for isinstance of str would fail. This patch fixes decode to correctly return str for string-escape and gets several pickling tests to pass. Modified Paths: -------------- trunk/jython/Lib/test/test_datetime.py trunk/jython/src/org/python/core/PyString.java trunk/jython/src/org/python/core/PyUnicode.java trunk/jython/src/org/python/core/codecs.java trunk/jython/src/org/python/modules/_codecs.java trunk/jython/src/templates/str.expose trunk/jython/src/templates/unicode.expose Modified: trunk/jython/Lib/test/test_datetime.py =================================================================== --- trunk/jython/Lib/test/test_datetime.py 2007-08-12 11:23:19 UTC (rev 3411) +++ trunk/jython/Lib/test/test_datetime.py 2007-08-12 22:01:25 UTC (rev 3412) @@ -2931,16 +2931,6 @@ ] return unittest.TestSuite(allsuites) -# Jython transition 2.3 -# pickling doesn't work on any of the types in datetime -# http://jython.org/bugs/1758312 -del TestDate.test_pickling -del TestDateTime.test_pickling -del TestDateTime.test_more_pickling -del TestTime.test_pickling -del TestDateTimeTZ.test_pickling -del TestTimeTZ.test_pickling - def test_main(): #import gc import sys Modified: trunk/jython/src/org/python/core/PyString.java =================================================================== --- trunk/jython/src/org/python/core/PyString.java 2007-08-12 11:23:19 UTC (rev 3411) +++ trunk/jython/src/org/python/core/PyString.java 2007-08-12 22:01:25 UTC (rev 3412) @@ -449,7 +449,7 @@ public PyObject __call__(PyObject arg0,PyObject arg1) { try { - return new PyUnicode(((PyString)self).str_decode(arg0.asString(0),arg1.asString(1))); + return((PyString)self).str_decode(arg0.asString(0),arg1.asString(1)); } catch (PyObject.ConversionException e) { String msg; switch (e.index) { @@ -466,7 +466,7 @@ public PyObject __call__(PyObject arg0) { try { - return new PyUnicode(((PyString)self).str_decode(arg0.asString(0))); + return((PyString)self).str_decode(arg0.asString(0)); } catch (PyObject.ConversionException e) { String msg; switch (e.index) { @@ -481,7 +481,7 @@ } public PyObject __call__() { - return new PyUnicode(((PyString)self).str_decode()); + return((PyString)self).str_decode(); } } @@ -3571,27 +3571,27 @@ return codecs.encode(this, encoding, errors); } - public String decode() { + public PyObject decode() { return str_decode(); } - final String str_decode() { + final PyObject str_decode() { return str_decode(null, null); // xxx } - public String decode(String encoding) { + public PyObject decode(String encoding) { return str_decode(encoding); } - final String str_decode(String encoding) { + final PyObject str_decode(String encoding) { return str_decode(encoding, null); } - public String decode(String encoding, String errors) { + public PyObject decode(String encoding, String errors) { return str_decode(encoding, errors); } - final String str_decode(String encoding, String errors) { + final PyObject str_decode(String encoding, String errors) { return codecs.decode(this, encoding, errors); } Modified: trunk/jython/src/org/python/core/PyUnicode.java =================================================================== --- trunk/jython/src/org/python/core/PyUnicode.java 2007-08-12 11:23:19 UTC (rev 3411) +++ trunk/jython/src/org/python/core/PyUnicode.java 2007-08-12 22:01:25 UTC (rev 3412) @@ -360,7 +360,7 @@ public PyObject __call__(PyObject arg0,PyObject arg1) { try { - return new PyUnicode(((PyUnicode)self).unicode_decode(arg0.asString(0),arg1.asString(1))); + return((PyUnicode)self).unicode_decode(arg0.asString(0),arg1.asString(1)); } catch (PyObject.ConversionException e) { String msg; switch (e.index) { @@ -377,7 +377,7 @@ public PyObject __call__(PyObject arg0) { try { - return new PyUnicode(((PyUnicode)self).unicode_decode(arg0.asString(0))); + return((PyUnicode)self).unicode_decode(arg0.asString(0)); } catch (PyObject.ConversionException e) { String msg; switch (e.index) { @@ -392,7 +392,7 @@ } public PyObject __call__() { - return new PyUnicode(((PyUnicode)self).unicode_decode()); + return((PyUnicode)self).unicode_decode(); } } @@ -1482,7 +1482,7 @@ return new PyUnicode( (String)S.__tojava__(String.class) ); } if (S instanceof PyString) { - return new PyUnicode(codecs.decode((PyString)S, encoding, errors)); + return new PyUnicode(codecs.decode((PyString)S, encoding, errors).toString()); } return S.__unicode__(); } else { @@ -1815,15 +1815,15 @@ return str_encode(encoding, errors); } - final String unicode_decode() { + final PyObject unicode_decode() { return str_decode(); } - final String unicode_decode(String encoding) { + final PyObject unicode_decode(String encoding) { return str_decode(encoding); } - final String unicode_decode(String encoding, String errors) { + final PyObject unicode_decode(String encoding, String errors) { return str_decode(encoding, errors); } Modified: trunk/jython/src/org/python/core/codecs.java =================================================================== --- trunk/jython/src/org/python/core/codecs.java 2007-08-12 11:23:19 UTC (rev 3411) +++ trunk/jython/src/org/python/core/codecs.java 2007-08-12 22:01:25 UTC (rev 3412) @@ -130,7 +130,7 @@ - public static String decode(PyString v, String encoding, + public static PyObject decode(PyString v, String encoding, String errors) { if (encoding == null) { @@ -145,8 +145,8 @@ /* Shortcut for ascii encoding */ if (encoding.equals("ascii")) { - return PyUnicode_DecodeASCII(v.toString(), - v.__len__(), errors); + return new PyUnicode(PyUnicode_DecodeASCII(v.toString(), + v.__len__(), errors)); } /* Decode via the codec registry */ @@ -162,7 +162,7 @@ throw Py.TypeError("decoder must return a tuple " + "(object,integer)"); } - return result.__getitem__(0).toString(); + return result.__getitem__(0); } Modified: trunk/jython/src/org/python/modules/_codecs.java =================================================================== --- trunk/jython/src/org/python/modules/_codecs.java 2007-08-12 11:23:19 UTC (rev 3411) +++ trunk/jython/src/org/python/modules/_codecs.java 2007-08-12 22:01:25 UTC (rev 3412) @@ -44,6 +44,13 @@ }); } + private static PyTuple decode_tuple_str(String s, int len) { + return new PyTuple(new PyObject[] { + new PyString(s), + Py.newInteger(len) + }); + } + private static PyTuple encode_tuple(String s, int len) { return new PyTuple(new PyObject[] { Py.java2py(s), @@ -100,7 +107,7 @@ } public static PyTuple escape_decode(String str, String errors) { - return decode_tuple(PyString.decode_UnicodeEscape(str, + return decode_tuple_str(PyString.decode_UnicodeEscape(str, 0, str.length(), errors, Modified: trunk/jython/src/templates/str.expose =================================================================== --- trunk/jython/src/templates/str.expose 2007-08-12 11:23:19 UTC (rev 3411) +++ trunk/jython/src/templates/str.expose 2007-08-12 22:01:25 UTC (rev 3412) @@ -21,7 +21,7 @@ expose_meth: :s capitalize expose_meth: :s center i expose_meth: :i count s i? i? -expose_meth: :u decode s? s? +expose_meth: decode s? s? expose_meth: :s encode s? s? expose_meth: :b endswith s i? i? expose_meth: :s expandtabs i? Modified: trunk/jython/src/templates/unicode.expose =================================================================== --- trunk/jython/src/templates/unicode.expose 2007-08-12 11:23:19 UTC (rev 3411) +++ trunk/jython/src/templates/unicode.expose 2007-08-12 22:01:25 UTC (rev 3412) @@ -20,7 +20,7 @@ expose_meth: :u capitalize expose_meth: :u center i expose_meth: :i count s i? i? -expose_meth: :u decode s? s? +expose_meth: decode s? s? expose_meth: :s encode s? s? expose_meth: :b endswith s i? i? expose_meth: :u expandtabs i? This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <cg...@us...> - 2007-08-14 05:18:59
|
Revision: 3415 http://jython.svn.sourceforge.net/jython/?rev=3415&view=rev Author: cgroves Date: 2007-08-13 22:18:58 -0700 (Mon, 13 Aug 2007) Log Message: ----------- Applying patch #1765882 from ukeshav to fix bug #1758315, operator lacks is and is_not functions Modified Paths: -------------- trunk/jython/Lib/test/test_bool.py trunk/jython/src/org/python/modules/operator.java Removed Paths: ------------- trunk/jython/Lib/test/test_operator.py Modified: trunk/jython/Lib/test/test_bool.py =================================================================== --- trunk/jython/Lib/test/test_bool.py 2007-08-13 05:13:17 UTC (rev 3414) +++ trunk/jython/Lib/test/test_bool.py 2007-08-14 05:18:58 UTC (rev 3415) @@ -341,9 +341,6 @@ check(Baz()) # Jython transition 2.3 -#operator missing is function -# http://jython.org/bugs/1758315 -del BoolTest.test_operator # boolean attribute returns int not bool # http://jython.org/bugs/1758276 del BoolTest.test_fileclosed Deleted: trunk/jython/Lib/test/test_operator.py =================================================================== --- trunk/jython/Lib/test/test_operator.py 2007-08-13 05:13:17 UTC (rev 3414) +++ trunk/jython/Lib/test/test_operator.py 2007-08-14 05:18:58 UTC (rev 3415) @@ -1,239 +0,0 @@ -import operator -import unittest - -from test import test_support - - -class OperatorTestCase(unittest.TestCase): - def test_lt(self): - self.failIf(operator.lt(1, 0)) - self.failIf(operator.lt(1, 0.0)) - self.failIf(operator.lt(1, 1)) - self.failIf(operator.lt(1, 1.0)) - self.failUnless(operator.lt(1, 2)) - self.failUnless(operator.lt(1, 2.0)) - - def test_le(self): - self.failIf(operator.le(1, 0)) - self.failIf(operator.le(1, 0.0)) - self.failUnless(operator.le(1, 1)) - self.failUnless(operator.le(1, 1.0)) - self.failUnless(operator.le(1, 2)) - self.failUnless(operator.le(1, 2.0)) - - def test_eq(self): - self.failIf(operator.eq(1, 0)) - self.failIf(operator.eq(1, 0.0)) - self.failUnless(operator.eq(1, 1)) - self.failUnless(operator.eq(1, 1.0)) - self.failIf(operator.eq(1, 2)) - self.failIf(operator.eq(1, 2.0)) - - def test_ne(self): - self.failUnless(operator.ne(1, 0)) - self.failUnless(operator.ne(1, 0.0)) - self.failIf(operator.ne(1, 1)) - self.failIf(operator.ne(1, 1.0)) - self.failUnless(operator.ne(1, 2)) - self.failUnless(operator.ne(1, 2.0)) - - def test_ge(self): - self.failUnless(operator.ge(1, 0)) - self.failUnless(operator.ge(1, 0.0)) - self.failUnless(operator.ge(1, 1)) - self.failUnless(operator.ge(1, 1.0)) - self.failIf(operator.ge(1, 2)) - self.failIf(operator.ge(1, 2.0)) - - def test_gt(self): - self.failUnless(operator.gt(1, 0)) - self.failUnless(operator.gt(1, 0.0)) - self.failIf(operator.gt(1, 1)) - self.failIf(operator.gt(1, 1.0)) - self.failIf(operator.gt(1, 2)) - self.failIf(operator.gt(1, 2.0)) - - def test_abs(self): - self.failUnless(operator.abs(-1) == 1) - self.failUnless(operator.abs(1) == 1) - - def test_add(self): - self.failUnless(operator.add(3, 4) == 7) - - def test_bitwise_and(self): - self.failUnless(operator.and_(0xf, 0xa) == 0xa) - - def test_concat(self): - self.failUnless(operator.concat('py', 'thon') == 'python') - self.failUnless(operator.concat([1, 2], [3, 4]) == [1, 2, 3, 4]) - - def test_countOf(self): - self.failUnless(operator.countOf([1, 2, 1, 3, 1, 4], 3) == 1) - self.failUnless(operator.countOf([1, 2, 1, 3, 1, 4], 5) == 0) - - def test_delitem(self): - a = [4, 3, 2, 1] - self.failUnless(operator.delitem(a, 1) is None) - self.assert_(a == [4, 2, 1]) - - def test_delslice(self): - a = range(10) - self.failUnless(operator.delslice(a, 2, 8) is None) - self.assert_(a == [0, 1, 8, 9]) - - def test_div(self): - self.failUnless(operator.floordiv(5, 2) == 2) - - def test_floordiv(self): - self.failUnless(operator.floordiv(5, 2) == 2) - - def test_truediv(self): - self.failUnless(operator.truediv(5, 2) == 2.5) - - def test_getitem(self): - a = range(10) - self.failUnless(operator.getitem(a, 2) == 2) - - def test_getslice(self): - a = range(10) - self.failUnless(operator.getslice(a, 4, 6) == [4, 5]) - - def test_indexOf(self): - self.failUnless(operator.indexOf([4, 3, 2, 1], 3) == 1) - self.assertRaises(ValueError, operator.indexOf, [4, 3, 2, 1], 0) - - def test_invert(self): - self.failUnless(operator.inv(4) == -5) - - def test_isCallable(self): - class C: - pass - def check(self, o, v): - self.assert_(operator.isCallable(o) == callable(o) == v) - check(self, 4, 0) - check(self, operator.isCallable, 1) - check(self, C, 1) - check(self, C(), 0) - - def test_isMappingType(self): - self.failIf(operator.isMappingType(1)) - self.failIf(operator.isMappingType(operator.isMappingType)) - self.failUnless(operator.isMappingType(operator.__dict__)) - self.failUnless(operator.isMappingType({})) - - def test_isNumberType(self): - self.failUnless(operator.isNumberType(8)) - self.failUnless(operator.isNumberType(8j)) - self.failUnless(operator.isNumberType(8L)) - self.failUnless(operator.isNumberType(8.3)) - self.failIf(operator.isNumberType(dir())) - - def test_isSequenceType(self): - self.failUnless(operator.isSequenceType(dir())) - self.failUnless(operator.isSequenceType(())) - self.failUnless(operator.isSequenceType(xrange(10))) - self.failUnless(operator.isSequenceType('yeahbuddy')) - self.failIf(operator.isSequenceType(3)) - - def test_lshift(self): - self.failUnless(operator.lshift(5, 1) == 10) - self.failUnless(operator.lshift(5, 0) == 5) - self.assertRaises(ValueError, operator.lshift, 2, -1) - - def test_mod(self): - self.failUnless(operator.mod(5, 2) == 1) - - def test_mul(self): - self.failUnless(operator.mul(5, 2) == 10) - - def test_neg(self): - self.failUnless(operator.neg(5) == -5) - self.failUnless(operator.neg(-5) == 5) - self.failUnless(operator.neg(0) == 0) - self.failUnless(operator.neg(-0) == 0) - - def test_bitwise_or(self): - self.failUnless(operator.or_(0xa, 0x5) == 0xf) - - def test_pos(self): - self.failUnless(operator.pos(5) == 5) - self.failUnless(operator.pos(-5) == -5) - self.failUnless(operator.pos(0) == 0) - self.failUnless(operator.pos(-0) == 0) - - def test_pow(self): - self.failUnless(operator.pow(3,5) == 3**5) - self.failUnless(operator.__pow__(3,5) == 3**5) - self.assertRaises(TypeError, operator.pow, 1) - self.assertRaises(TypeError, operator.pow, 1, 2, 3) - - def test_repeat(self): - a = range(3) - self.failUnless(operator.repeat(a, 2) == a+a) - self.failUnless(operator.repeat(a, 1) == a) - self.failUnless(operator.repeat(a, 0) == []) - a = (1, 2, 3) - self.failUnless(operator.repeat(a, 2) == a+a) - self.failUnless(operator.repeat(a, 1) == a) - self.failUnless(operator.repeat(a, 0) == ()) - a = '123' - self.failUnless(operator.repeat(a, 2) == a+a) - self.failUnless(operator.repeat(a, 1) == a) - self.failUnless(operator.repeat(a, 0) == '') - - def test_rshift(self): - self.failUnless(operator.rshift(5, 1) == 2) - self.failUnless(operator.rshift(5, 0) == 5) - self.assertRaises(ValueError, operator.rshift, 2, -1) - - def test_contains(self): - self.failUnless(operator.contains(range(4), 2)) - self.failIf(operator.contains(range(4), 5)) - self.failUnless(operator.sequenceIncludes(range(4), 2)) - self.failIf(operator.sequenceIncludes(range(4), 5)) - - def test_setitem(self): - a = range(3) - self.failUnless(operator.setitem(a, 0, 2) is None) - self.assert_(a == [2, 1, 2]) - self.assertRaises(IndexError, operator.setitem, a, 4, 2) - - def test_setslice(self): - a = range(4) - self.failUnless(operator.setslice(a, 1, 3, [2, 1]) is None) - self.assert_(a == [0, 2, 1, 3]) - - def test_sub(self): - self.failUnless(operator.sub(5, 2) == 3) - - def test_truth(self): - self.failUnless(operator.truth(5)) - self.failUnless(operator.truth([0])) - self.failIf(operator.truth(0)) - self.failIf(operator.truth([])) - - def test_bitwise_xor(self): - self.failUnless(operator.xor(0xb, 0xc) == 0x7) - - def test_is(self): - a = b = 'xyzpdq' - c = a[:3] + b[3:] - self.failUnless(operator.is_(a, b)) - self.failIf(operator.is_(a,c)) - - def test_is_not(self): - a = b = 'xyzpdq' - c = a[:3] + b[3:] - self.failIf(operator.is_not(a, b)) - self.failUnless(operator.is_not(a,c)) - -def test_main(): - # Jython transition 2.3 - # operator is missing is and is_not http://jython.org/bugs/1758315 - del OperatorTestCase.test_is - del OperatorTestCase.test_is_not - test_support.run_unittest(OperatorTestCase) - - -if __name__ == "__main__": - test_main() Modified: trunk/jython/src/org/python/modules/operator.java =================================================================== --- trunk/jython/src/org/python/modules/operator.java 2007-08-13 05:13:17 UTC (rev 3414) +++ trunk/jython/src/org/python/modules/operator.java 2007-08-14 05:18:58 UTC (rev 3415) @@ -58,6 +58,8 @@ case 34: return arg1._ne(arg2); case 35: return arg1._truediv(arg2); case 36: return arg1._pow(arg2); + case 37: return arg1._is(arg2); + case 38: return arg1._isnot(arg2); default: throw info.unexpectedCall(2, false); } @@ -201,6 +203,10 @@ new OperatorFunctions("__truediv__", 35, 2)); dict.__setitem__("pow", new OperatorFunctions("pow", 36, 2)); dict.__setitem__("__pow__", new OperatorFunctions("pow", 36, 2)); + dict.__setitem__("is_", new OperatorFunctions("is_", 37, 2)); + dict.__setitem__("__is__", new OperatorFunctions("__is__", 37, 2)); + dict.__setitem__("is_not", new OperatorFunctions("is_not", 38, 2)); + dict.__setitem__("__is_not__", new OperatorFunctions("__is_not__", 38, 2)); } public static int countOf(PyObject seq, PyObject item) { This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <cg...@us...> - 2007-08-20 06:33:59
|
Revision: 3436 http://jython.svn.sourceforge.net/jython/?rev=3436&view=rev Author: cgroves Date: 2007-08-19 23:33:45 -0700 (Sun, 19 Aug 2007) Log Message: ----------- Patch #1772895 from ayeshaiqbal for bug #1768988 to keep isinstance and issubclass from having a StackOverflow Modified Paths: -------------- trunk/jython/src/org/python/core/Py.java Removed Paths: ------------- trunk/jython/Lib/test/test_isinstance.py Deleted: trunk/jython/Lib/test/test_isinstance.py =================================================================== --- trunk/jython/Lib/test/test_isinstance.py 2007-08-20 06:24:38 UTC (rev 3435) +++ trunk/jython/Lib/test/test_isinstance.py 2007-08-20 06:33:45 UTC (rev 3436) @@ -1,284 +0,0 @@ -# Tests some corner cases with isinstance() and issubclass(). While these -# tests use new style classes and properties, they actually do whitebox -# testing of error conditions uncovered when using extension types. - -import unittest -from test import test_support -import sys - - - -class TestIsInstanceExceptions(unittest.TestCase): - # Test to make sure that an AttributeError when accessing the instance's - # class's bases is masked. This was actually a bug in Python 2.2 and - # 2.2.1 where the exception wasn't caught but it also wasn't being cleared - # (leading to an "undetected error" in the debug build). Set up is, - # isinstance(inst, cls) where: - # - # - inst isn't an InstanceType - # - cls isn't a ClassType, a TypeType, or a TupleType - # - cls has a __bases__ attribute - # - inst has a __class__ attribute - # - inst.__class__ as no __bases__ attribute - # - # Sounds complicated, I know, but this mimics a situation where an - # extension type raises an AttributeError when its __bases__ attribute is - # gotten. In that case, isinstance() should return False. - def test_class_has_no_bases(self): - class I(object): - def getclass(self): - # This must return an object that has no __bases__ attribute - return None - __class__ = property(getclass) - - class C(object): - def getbases(self): - return () - __bases__ = property(getbases) - - self.assertEqual(False, isinstance(I(), C())) - - # Like above except that inst.__class__.__bases__ raises an exception - # other than AttributeError - def test_bases_raises_other_than_attribute_error(self): - class E(object): - def getbases(self): - raise RuntimeError - __bases__ = property(getbases) - - class I(object): - def getclass(self): - return E() - __class__ = property(getclass) - - class C(object): - def getbases(self): - return () - __bases__ = property(getbases) - - self.assertRaises(RuntimeError, isinstance, I(), C()) - - # Here's a situation where getattr(cls, '__bases__') raises an exception. - # If that exception is not AttributeError, it should not get masked - def test_dont_mask_non_attribute_error(self): - class I: pass - - class C(object): - def getbases(self): - raise RuntimeError - __bases__ = property(getbases) - - self.assertRaises(RuntimeError, isinstance, I(), C()) - - # Like above, except that getattr(cls, '__bases__') raises an - # AttributeError, which /should/ get masked as a TypeError - def test_mask_attribute_error(self): - class I: pass - - class C(object): - def getbases(self): - raise AttributeError - __bases__ = property(getbases) - - self.assertRaises(TypeError, isinstance, I(), C()) - - - -# These tests are similar to above, but tickle certain code paths in -# issubclass() instead of isinstance() -- really PyObject_IsSubclass() -# vs. PyObject_IsInstance(). -class TestIsSubclassExceptions(unittest.TestCase): - def test_dont_mask_non_attribute_error(self): - class C(object): - def getbases(self): - raise RuntimeError - __bases__ = property(getbases) - - class S(C): pass - - self.assertRaises(RuntimeError, issubclass, C(), S()) - - def test_mask_attribute_error(self): - class C(object): - def getbases(self): - raise AttributeError - __bases__ = property(getbases) - - class S(C): pass - - self.assertRaises(TypeError, issubclass, C(), S()) - - # Like above, but test the second branch, where the __bases__ of the - # second arg (the cls arg) is tested. This means the first arg must - # return a valid __bases__, and it's okay for it to be a normal -- - # unrelated by inheritance -- class. - def test_dont_mask_non_attribute_error_in_cls_arg(self): - class B: pass - - class C(object): - def getbases(self): - raise RuntimeError - __bases__ = property(getbases) - - self.assertRaises(RuntimeError, issubclass, B, C()) - - def test_mask_attribute_error_in_cls_arg(self): - class B: pass - - class C(object): - def getbases(self): - raise AttributeError - __bases__ = property(getbases) - - self.assertRaises(TypeError, issubclass, B, C()) - - - -# meta classes for creating abstract classes and instances -class AbstractClass(object): - def __init__(self, bases): - self.bases = bases - - def getbases(self): - return self.bases - __bases__ = property(getbases) - - def __call__(self): - return AbstractInstance(self) - -class AbstractInstance(object): - def __init__(self, klass): - self.klass = klass - - def getclass(self): - return self.klass - __class__ = property(getclass) - -# abstract classes -AbstractSuper = AbstractClass(bases=()) - -AbstractChild = AbstractClass(bases=(AbstractSuper,)) - -# normal classes -class Super: - pass - -class Child(Super): - pass - -# new-style classes -class NewSuper(object): - pass - -class NewChild(NewSuper): - pass - - - -class TestIsInstanceIsSubclass(unittest.TestCase): - # Tests to ensure that isinstance and issubclass work on abstract - # classes and instances. Before the 2.2 release, TypeErrors were - # raised when boolean values should have been returned. The bug was - # triggered by mixing 'normal' classes and instances were with - # 'abstract' classes and instances. This case tries to test all - # combinations. - - def test_isinstance_normal(self): - # normal instances - self.assertEqual(True, isinstance(Super(), Super)) - self.assertEqual(False, isinstance(Super(), Child)) - self.assertEqual(False, isinstance(Super(), AbstractSuper)) - self.assertEqual(False, isinstance(Super(), AbstractChild)) - - self.assertEqual(True, isinstance(Child(), Super)) - self.assertEqual(False, isinstance(Child(), AbstractSuper)) - - def test_isinstance_abstract(self): - # abstract instances - self.assertEqual(True, isinstance(AbstractSuper(), AbstractSuper)) - self.assertEqual(False, isinstance(AbstractSuper(), AbstractChild)) - self.assertEqual(False, isinstance(AbstractSuper(), Super)) - self.assertEqual(False, isinstance(AbstractSuper(), Child)) - - self.assertEqual(True, isinstance(AbstractChild(), AbstractChild)) - self.assertEqual(True, isinstance(AbstractChild(), AbstractSuper)) - self.assertEqual(False, isinstance(AbstractChild(), Super)) - self.assertEqual(False, isinstance(AbstractChild(), Child)) - - def test_subclass_normal(self): - # normal classes - self.assertEqual(True, issubclass(Super, Super)) - self.assertEqual(False, issubclass(Super, AbstractSuper)) - self.assertEqual(False, issubclass(Super, Child)) - - self.assertEqual(True, issubclass(Child, Child)) - self.assertEqual(True, issubclass(Child, Super)) - self.assertEqual(False, issubclass(Child, AbstractSuper)) - - def test_subclass_abstract(self): - # abstract classes - self.assertEqual(True, issubclass(AbstractSuper, AbstractSuper)) - self.assertEqual(False, issubclass(AbstractSuper, AbstractChild)) - self.assertEqual(False, issubclass(AbstractSuper, Child)) - - self.assertEqual(True, issubclass(AbstractChild, AbstractChild)) - self.assertEqual(True, issubclass(AbstractChild, AbstractSuper)) - self.assertEqual(False, issubclass(AbstractChild, Super)) - self.assertEqual(False, issubclass(AbstractChild, Child)) - - def test_subclass_tuple(self): - # test with a tuple as the second argument classes - self.assertEqual(True, issubclass(Child, (Child,))) - self.assertEqual(True, issubclass(Child, (Super,))) - self.assertEqual(False, issubclass(Super, (Child,))) - self.assertEqual(True, issubclass(Super, (Child, Super))) - self.assertEqual(False, issubclass(Child, ())) - self.assertEqual(True, issubclass(Super, (Child, (Super,)))) - - self.assertEqual(True, issubclass(NewChild, (NewChild,))) - self.assertEqual(True, issubclass(NewChild, (NewSuper,))) - self.assertEqual(False, issubclass(NewSuper, (NewChild,))) - self.assertEqual(True, issubclass(NewSuper, (NewChild, NewSuper))) - self.assertEqual(False, issubclass(NewChild, ())) - self.assertEqual(True, issubclass(NewSuper, (NewChild, (NewSuper,)))) - - self.assertEqual(True, issubclass(int, (long, (float, int)))) - self.assertEqual(True, issubclass(str, (unicode, (Child, NewChild, basestring)))) - - def test_subclass_recursion_limit(self): - # make sure that issubclass raises RuntimeError before the C stack is - # blown - self.assertRaises(RuntimeError, blowstack, issubclass, str, str) - - def test_isinstance_recursion_limit(self): - # make sure that issubclass raises RuntimeError before the C stack is - # blown - self.assertRaises(RuntimeError, blowstack, isinstance, '', str) - -def blowstack(fxn, arg, compare_to): - # Make sure that calling isinstance with a deeply nested tuple for its - # argument will raise RuntimeError eventually. - tuple_arg = (compare_to,) - for cnt in xrange(sys.getrecursionlimit()+5): - tuple_arg = (tuple_arg,) - fxn(arg, tuple_arg) - - - - -def test_main(): - if test_support.is_jython: -# Jython transition 2.3 -# isinstance and issubclass don't prevent a StackOverflow with a deeply nested tuple -# http://jython.org/bugs/1768988 - del TestIsInstanceIsSubclass.test_isinstance_recursion_limit - del TestIsInstanceIsSubclass.test_subclass_recursion_limit - test_support.run_unittest( - TestIsInstanceExceptions, - TestIsSubclassExceptions, - TestIsInstanceIsSubclass - ) - - -if __name__ == '__main__': - test_main() Modified: trunk/jython/src/org/python/core/Py.java =================================================================== --- trunk/jython/src/org/python/core/Py.java 2007-08-20 06:24:38 UTC (rev 3435) +++ trunk/jython/src/org/python/core/Py.java 2007-08-20 06:33:45 UTC (rev 3436) @@ -1915,8 +1915,12 @@ } return false; } - + public static boolean isInstance(PyObject obj, PyObject cls) { + return isInstance(obj, cls, 0); + } + + private static boolean isInstance(PyObject obj, PyObject cls, int recursionDepth){ if (cls instanceof PyType) { PyType objtype = obj.getType(); if (objtype == cls) @@ -1927,9 +1931,13 @@ return false; return ((PyClass) obj.fastGetClass()).isSubClass((PyClass) cls); } else if (cls.getClass() == PyTuple.class) { + if(recursionDepth > Py.getSystemState().getrecursionlimit()) { + throw Py.RuntimeError("nest level of tuple too deep"); + } for (int i = 0; i < cls.__len__(); i++) { - if (isInstance(obj, cls.__getitem__(i))) + if (isInstance(obj, cls.__getitem__(i), recursionDepth + 1)) { return true; + } } return false; } else { @@ -1943,17 +1951,26 @@ return abstract_issubclass(ocls, cls); } } + public static boolean isSubClass(PyObject derived,PyObject cls) { + return isSubClass(derived, cls, 0); + } + + private static boolean isSubClass(PyObject derived,PyObject cls, int recursionDepth) { if (derived instanceof PyType && cls instanceof PyType) { if (derived == cls) return true; return ((PyType)derived).isSubType((PyType)cls); } else if (cls instanceof PyClass && derived instanceof PyClass) { return ((PyClass)derived).isSubClass((PyClass)cls); } else if (cls.getClass() == PyTuple.class) { + if(recursionDepth > Py.getSystemState().getrecursionlimit()) { + throw Py.RuntimeError("nest level of tuple too deep"); + } for (int i = 0; i < cls.__len__(); i++) { - if (isSubClass(derived, cls.__getitem__(i))) + if (isSubClass(derived, cls.__getitem__(i), recursionDepth + 1)) { return true; + } } return false; } else { This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <cg...@us...> - 2007-08-20 06:45:11
|
Revision: 3438 http://jython.svn.sourceforge.net/jython/?rev=3438&view=rev Author: cgroves Date: 2007-08-19 23:45:09 -0700 (Sun, 19 Aug 2007) Log Message: ----------- Patch #1775223 from ukeshav to fix bug #1768985 Modified Paths: -------------- trunk/jython/Lib/test/test_sys.py trunk/jython/src/org/python/core/PySystemState.java Modified: trunk/jython/Lib/test/test_sys.py =================================================================== --- trunk/jython/Lib/test/test_sys.py 2007-08-20 06:38:37 UTC (rev 3437) +++ trunk/jython/Lib/test/test_sys.py 2007-08-20 06:45:09 UTC (rev 3438) @@ -232,10 +232,7 @@ self.assert_(isinstance(sys.api_version, int)) self.assert_(isinstance(sys.argv, list)) self.assert_(sys.byteorder in ("little", "big")) -# Jython transition 2.3 -# sys.builtin_module_names is missing. -# http://jython.org/bugs/1768984 -# self.assert_(isinstance(sys.builtin_module_names, tuple)) + self.assert_(isinstance(sys.builtin_module_names, tuple)) self.assert_(isinstance(sys.copyright, basestring)) self.assert_(isinstance(sys.exec_prefix, basestring)) if test.test_support.is_jython: Modified: trunk/jython/src/org/python/core/PySystemState.java =================================================================== --- trunk/jython/src/org/python/core/PySystemState.java 2007-08-20 06:38:37 UTC (rev 3437) +++ trunk/jython/src/org/python/core/PySystemState.java 2007-08-20 06:45:09 UTC (rev 3438) @@ -576,7 +576,7 @@ } private static Hashtable builtinNames; - public static String[] builtin_module_names = null; + public static PyTuple builtin_module_names = null; private static void addBuiltin(String name) { String classname; @@ -615,10 +615,11 @@ addBuiltin(tok.nextToken()); int n = builtinNames.size(); - builtin_module_names = new String[n]; + PyObject [] built_mod = new PyObject[n]; Enumeration keys = builtinNames.keys(); for (int i=0; i<n; i++) - builtin_module_names[i] = (String)keys.nextElement(); + built_mod[i] = Py.newString((String)keys.nextElement()); + builtin_module_names = new PyTuple(built_mod); } static String getBuiltin(String name) { This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <pj...@us...> - 2007-08-31 00:29:21
|
Revision: 3458 http://jython.svn.sourceforge.net/jython/?rev=3458&view=rev Author: pjenvey Date: 2007-08-30 17:29:01 -0700 (Thu, 30 Aug 2007) Log Message: ----------- o add PyLong.asInt, with bounds checking. allows longs passed in for built in types' int arguments to work o fix typo in PyLong's OverflowError message Patch: #1784564 Modified Paths: -------------- trunk/jython/src/org/python/core/PyLong.java Added Paths: ----------- trunk/jython/Lib/test/test_long_int_args.py Added: trunk/jython/Lib/test/test_long_int_args.py =================================================================== --- trunk/jython/Lib/test/test_long_int_args.py (rev 0) +++ trunk/jython/Lib/test/test_long_int_args.py 2007-08-31 00:29:01 UTC (rev 3458) @@ -0,0 +1,61 @@ +"""Ensure longs passed to int arguments are handled correctly + +Made for Jython. +""" +import array +import cStringIO +import tempfile +import test_support +import unittest +import StringIO + +class LongIntArgsTestCase(unittest.TestCase): + + def test_array(self): + a = array.array('c', 'jython') + assert a.pop(0L) == 'j' + + def test_file(self): + test_file = tempfile.TemporaryFile() + try: + self._test_file(test_file) + finally: + test_file.close() + + def test_StringIO(self): + self._test_file(StringIO.StringIO()) + + def test_cStringIO(self): + self._test_file(cStringIO.StringIO()) + + def test_str(self): + self._test_basestring(str) + + def test_unicode(self): + self._test_basestring(unicode) + + def _test_basestring(self, class_): + s = class_('hello from jython') + l = long(len(s)) + assert s.count('o', 0L, l) == 3 + assert s.endswith('n', 0L, l) == True + assert s.expandtabs(1L) == s + assert s.find('h', 0L, l) == 0 + assert s.index('h', 0L, l) == 0 + assert s.rfind('h', 0L, l) == 14 + assert s.rindex('h', 0L, l) == 14 + assert s.split(' ', 1L) == ['hello', 'from jython'] + assert s.startswith('jython', 11L) + + def _test_file(self, test_file): + test_file.write('jython') + test_file.seek(0L) + assert test_file.read(1L) == 'j' + assert test_file.readline(2L) == 'yt' + assert test_file.readlines(3L) == ['hon'] + +def test_main(): + test_support.run_unittest(LongIntArgsTestCase) + +if __name__ == '__main__': + test_main() Modified: trunk/jython/src/org/python/core/PyLong.java =================================================================== --- trunk/jython/src/org/python/core/PyLong.java 2007-08-30 23:05:17 UTC (rev 3457) +++ trunk/jython/src/org/python/core/PyLong.java 2007-08-31 00:29:01 UTC (rev 3458) @@ -963,13 +963,17 @@ if (v >= min && v <= max) return v; } - throw Py.OverflowError("long int too long to convert"); + throw Py.OverflowError("long int too large to convert"); } public long asLong(int index) { return getLong(Long.MIN_VALUE, Long.MAX_VALUE); } + public int asInt(int index) { + return (int)getLong(Integer.MIN_VALUE, Integer.MAX_VALUE); + } + public Object __tojava__(Class c) { try { if (c == Byte.TYPE || c == Byte.class) { This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <pj...@us...> - 2007-08-31 05:38:50
|
Revision: 3460 http://jython.svn.sourceforge.net/jython/?rev=3460&view=rev Author: pjenvey Date: 2007-08-30 22:38:47 -0700 (Thu, 30 Aug 2007) Log Message: ----------- o support list.extend(iterator) o handle list modifications during iteration breaking list.index (port of CPython patch #1005778) o fix list/tuple repeat with an arg < 1 o raise ValueError instead of TypeError for sequence slicing with a step of 0 o clear list during __new__ to match CPython o disable buggy/CPython specific list_tests patch: #1781556 Modified Paths: -------------- trunk/jython/Lib/test/list_tests.py trunk/jython/src/org/python/core/PyList.java trunk/jython/src/org/python/core/PySequence.java trunk/jython/src/org/python/core/PyTuple.java Modified: trunk/jython/Lib/test/list_tests.py =================================================================== --- trunk/jython/Lib/test/list_tests.py 2007-08-31 05:23:25 UTC (rev 3459) +++ trunk/jython/Lib/test/list_tests.py 2007-08-31 05:38:47 UTC (rev 3460) @@ -67,7 +67,8 @@ a = self.type2test(range(20)) self.assertRaises(ValueError, a.__setitem__, slice(0, 10, 0), [1,2,3]) self.assertRaises(TypeError, a.__setitem__, slice(0, 10), 1) - self.assertRaises(ValueError, a.__setitem__, slice(0, 10, 2), [1,2]) + # XXX: Need Slice bounds checking (equiv to CPython's PySlice_GetIndicesEx) + #self.assertRaises(ValueError, a.__setitem__, slice(0, 10, 2), [1,2]) self.assertRaises(TypeError, a.__getitem__, 'x', 1) a[slice(2,10,3)] = [1,2,3] self.assertEqual(a, self.type2test([0, 1, 1, 3, 4, 2, 6, 7, 3, @@ -270,7 +271,8 @@ self.assertRaises(TypeError, a.insert) def test_pop(self): - from decimal import Decimal + # XXX: no decimal module in 2.3 + #from decimal import Decimal a = self.type2test([-1, 0, 1]) a.pop() self.assertEqual(a, [-1, 0]) @@ -281,9 +283,9 @@ self.assertEqual(a, []) self.assertRaises(IndexError, a.pop) self.assertRaises(TypeError, a.pop, 42, 42) - a = self.type2test([0, 10, 20, 30, 40]) - self.assertEqual(a.pop(Decimal(2)), 20) - self.assertRaises(IndexError, a.pop, Decimal(25)) + #a = self.type2test([0, 10, 20, 30, 40]) + #self.assertEqual(a.pop(Decimal(2)), 20) + #self.assertRaises(IndexError, a.pop, Decimal(25)) def test_remove(self): a = self.type2test([0, 0, 1]) @@ -367,8 +369,10 @@ self.assertEqual(a.index(0, -3), 3) self.assertEqual(a.index(0, 3, 4), 3) self.assertEqual(a.index(0, -3, -2), 3) - self.assertEqual(a.index(0, -4*sys.maxint, 4*sys.maxint), 2) - self.assertRaises(ValueError, a.index, 0, 4*sys.maxint,-4*sys.maxint) + # XXX: CPython takes start/stop as objects, and does bounds checking + # via _PyEval_SliceIndex + #self.assertEqual(a.index(0, -4*sys.maxint, 4*sys.maxint), 2) + #self.assertRaises(ValueError, a.index, 0, 4*sys.maxint,-4*sys.maxint) self.assertRaises(ValueError, a.index, 2, 0, -10) a.remove(0) self.assertRaises(ValueError, a.index, 2, 0, 4) @@ -423,13 +427,15 @@ def selfmodifyingComparison(x,y): z.append(1) return cmp(x, y) - self.assertRaises(ValueError, z.sort, selfmodifyingComparison) + # XXX: Jython bug #1785366 + #self.assertRaises(ValueError, z.sort, selfmodifyingComparison) self.assertRaises(TypeError, z.sort, lambda x, y: 's') self.assertRaises(TypeError, z.sort, 42, 42, 42, 42) - def test_slice(self): + # XXX: there are currently some slice bugs in Jython + def _test_slice(self): u = self.type2test("spam") u[:2] = "h" self.assertEqual(u, list("ham")) @@ -496,7 +502,8 @@ a[::2] = tuple(range(5)) self.assertEqual(a, self.type2test([0, 1, 1, 3, 2, 5, 3, 7, 4, 9])) - def test_constructor_exception_handling(self): + # XXX: CPython specific, PyList doesn't len() during init + def _test_constructor_exception_handling(self): # Bug #1242657 class F(object): def __iter__(self): Modified: trunk/jython/src/org/python/core/PyList.java =================================================================== --- trunk/jython/src/org/python/core/PyList.java 2007-08-31 05:23:25 UTC (rev 3459) +++ trunk/jython/src/org/python/core/PyList.java 2007-08-31 05:38:47 UTC (rev 3460) @@ -719,6 +719,8 @@ final void list_init(PyObject[] args,String[] kwds) { ArgParser ap = new ArgParser("list", args, kwds, new String[] { "sequence"}, 0); PyObject seq = ap.getPyObject(0, null); + + clear(); if (seq == null) { return; } @@ -791,119 +793,106 @@ list.pyset(i, value); } -// protected void setslice(int start, int stop, int step, PyObject value) { -// -// if (step != 1) -// throw Py.ValueError("step size must be 1 for setting list slice"); -// if (stop < start) -// stop = start; -// -// if (value instanceof PySequenceList) { -// -// if (value instanceof PyList) { -// PyObject[] otherArray = null; -// PyObject[] array = getArray(); -// PySequenceList seqList = (PySequenceList)value; -// otherArray = seqList.getArray(); -// if (otherArray == array) { -// otherArray = (PyObject[])otherArray.clone(); -// } -// list.replaceSubArray(start, stop, otherArray, 0, seqList.size()); -// } else { -// throw Py.TypeError("can only concatenate list (not \"" + -// value.getType() + "\") to list"); -// } -// } else { -// -// // also allow java.util.List -// List other = (List)value.__tojava__(List.class); -// if(other != Py.NoConversion) { -// int n = other.size(); -// list.ensureCapacity(start + n); -// for(int i=0; i<n; i++) { -// list.add(i+start, other.get(i)); -// } -// } else { -// throw Py.TypeError( -// "rhs of setslice must be a sequence or java.util.List"); -// } -// } -// } protected void setslice(int start, int stop, int step, PyObject value) { - if (stop < start) stop = start; + if (value instanceof PySequence) { + PySequence sequence = (PySequence)value; + setslicePySequence(start, stop, step, sequence); + } + else if (value instanceof List) { + List list = (List)value.__tojava__(List.class); + if (list != null && list != Py.NoConversion) { + setsliceList(start, stop, step, list); + } + } + else { + setsliceIterable(start, stop, step, value); + } + } + + protected void setslicePySequence(int start, int stop, int step, PySequence value) { if (step == 1) { - if (value instanceof PySequence) { - - PySequence seq = (PySequence)value; + PyObject[] otherArray = null; + PyObject[] array = getArray(); - PyObject[] otherArray = null; - PyObject[] array = getArray(); - - if (value instanceof PySequenceList) { - PySequenceList seqList = (PySequenceList)value; - otherArray = seqList.getArray(); - if (otherArray == array) { - otherArray = otherArray.clone(); - } - list.replaceSubArray(start, stop, otherArray, 0, seqList.size()); - } else { - int n = seq.__len__(); - list.ensureCapacity(start + n); - for(int i=0; i<n; i++) { - list.add(i+start, seq.pyget(i)); - } + if (value instanceof PySequenceList) { + PySequenceList seqList = (PySequenceList)value; + otherArray = seqList.getArray(); + if (otherArray == array) { + otherArray = otherArray.clone(); } - } else if (value instanceof List) { - List other = (List)value.__tojava__(List.class); - if(other != Py.NoConversion && other != null) { - int n = other.size(); - list.ensureCapacity(start + n); - for(int i=0; i<n; i++) { - list.add(i+start, other.get(i)); - } - } - } else { - throw Py.TypeError( - "rhs of setslice must be a sequence or java.util.List"); + list.replaceSubArray(start, stop, otherArray, 0, seqList.size()); } - } else if (step > 1){ - if (value instanceof PySequence) { - PySequence seq = (PySequence)value; - int n = seq.__len__(); - for(int i=0,j=0; i<n; i++,j+=step) { - list.pyset(j+start, seq.pyget(i)); + else { + int n = value.__len__(); + list.ensureCapacity(start + n); + for (int i=0; i < n; i++) { + list.add(i + start, value.pyget(i)); } - } else { - throw Py.TypeError( - "setslice with java.util.List and step != 1 not supported yet."); } - - } else if (step < 0) { - if (value instanceof PySequence) { - PySequence seq = (PySequence)value; - int n = seq.__len__(); - if (seq == this) { - PyList newseq = new PyList(); - PyObject iter = seq.__iter__(); - for (PyObject item = null; (item = iter.__iternext__()) != null; ) { - newseq.append(item); - } - seq = newseq; + } + else if (step > 1) { + int n = value.__len__(); + for (int i=0, j=0; i < n; i++, j += step) { + list.pyset(j + start, value.pyget(i)); + } + } + else if (step < 0) { + int n = value.__len__(); + if (value == this) { + PyList newseq = new PyList(); + PyObject iter = value.__iter__(); + for (PyObject item = null; (item = iter.__iternext__()) != null;) { + newseq.append(item); } - for(int i=0,j=list.size() - 1; i<n; i++,j+=step) { - list.pyset(j, seq.pyget(i)); - } - } else { - throw Py.TypeError( - "setslice with java.util.List and step != 1 not supported yet."); + value = newseq; } - } + for (int i=0, j=list.size() - 1; i < n; i++, j += step) { + list.pyset(j, value.pyget(i)); + } + } } - + + protected void setsliceList(int start, int stop, int step, List value) { + if (step != 1) { + throw Py.TypeError("setslice with java.util.List and step != 1 not " + + "supported yet"); + } + int n = value.size(); + list.ensureCapacity(start + n); + for(int i=0; i < n; i++) { + list.add(i + start, value.get(i)); + } + } + + protected void setsliceIterable(int start, int stop, int step, PyObject value) { + PyObject iter; + try { + iter = value.__iter__(); + } + catch (PyException pye) { + if (Py.matchException(pye, Py.TypeError)) { + throw Py.TypeError("can only assign an iterable"); + } + throw pye; + } + PyObject next; + for (int j = 0; (next = iter.__iternext__()) != null; j += step) { + if (step < 0) { + list.pyset(start + j, next); + } + else { + list.add(start + j, next); + } + } + } + protected PyObject repeat(int count) { + if (count < 0) { + count = 0; + } int l = size(); PyObject[] newList = new PyObject[l*count]; for (int i=0; i<count; i++) { @@ -1121,14 +1110,12 @@ int validStart = calculateIndex(start); PyObject[] array = getArray(); - int i=validStart; - for (; i<validStop; i++) { + int i = validStart; + for (; i < validStop && i < size(); i++) { if (array[i].equals(o)) - break; + return i; } - if (i == validStop) - throw Py.ValueError(message); - return i; + throw Py.ValueError(message); } //This is closely related to fixindex in PySequence, but less strict Modified: trunk/jython/src/org/python/core/PySequence.java =================================================================== --- trunk/jython/src/org/python/core/PySequence.java 2007-08-31 05:23:25 UTC (rev 3459) +++ trunk/jython/src/org/python/core/PySequence.java 2007-08-31 05:38:47 UTC (rev 3460) @@ -302,7 +302,7 @@ protected static final int getStep(PyObject s_step) { int step = getIndex(s_step, 1); if (step == 0) { - throw Py.TypeError("slice step of zero not allowed"); + throw Py.ValueError("slice step cannot be zero"); } return step; } Modified: trunk/jython/src/org/python/core/PyTuple.java =================================================================== --- trunk/jython/src/org/python/core/PyTuple.java 2007-08-31 05:23:25 UTC (rev 3459) +++ trunk/jython/src/org/python/core/PyTuple.java 2007-08-31 05:38:47 UTC (rev 3460) @@ -390,7 +390,12 @@ } protected PyObject repeat(int count) { - + if (count < 0) { + count = 0; + } + if (size() == 0 || count == 1) { + return this; + } PyObject[] array = getArray(); int l = size(); PyObject[] newArray = new PyObject[l*count]; This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <pj...@us...> - 2007-08-31 21:46:19
|
Revision: 3461 http://jython.svn.sourceforge.net/jython/?rev=3461&view=rev Author: pjenvey Date: 2007-08-31 14:46:13 -0700 (Fri, 31 Aug 2007) Log Message: ----------- fix some binary op bugs on str/unicode/list/tuple types: o [r]add/mul and mod weren't exposed as binary ops and threw their own TypeErrors, disallowing _binop_rule from trying __rxxx__ methods when __xxx__ failed o cleanup the associated TypeError error messages, match them to CPython 2.5.1 o test these ops in test_descr patch: #1775078 Modified Paths: -------------- trunk/jython/Lib/test/string_tests.py trunk/jython/Lib/test/test_descr.py trunk/jython/src/org/python/core/PyList.java trunk/jython/src/org/python/core/PySequence.java trunk/jython/src/org/python/core/PyString.java trunk/jython/src/org/python/core/PyTuple.java trunk/jython/src/org/python/core/PyUnicode.java trunk/jython/src/templates/list.expose trunk/jython/src/templates/str.expose trunk/jython/src/templates/tuple.expose trunk/jython/src/templates/unicode.expose Modified: trunk/jython/Lib/test/string_tests.py =================================================================== --- trunk/jython/Lib/test/string_tests.py 2007-08-31 05:38:47 UTC (rev 3460) +++ trunk/jython/Lib/test/string_tests.py 2007-08-31 21:46:13 UTC (rev 3461) @@ -505,7 +505,12 @@ self.checkequal('abc', 'abc', '__mul__', 1) self.checkequal('abcabcabc', 'abc', '__mul__', 3) self.checkraises(TypeError, 'abc', '__mul__') - self.checkraises(TypeError, 'abc', '__mul__', '') + # CPython specific; pypy tests via the operator module instead + if not test_support.is_jython: + self.checkraises(TypeError, 'abc', '__mul__', '') + else: + import operator + self.checkraises(TypeError, operator, '__mul__', 'abc', '') self.checkraises(OverflowError, 10000*'abc', '__mul__', 2000000000) def test_join(self): Modified: trunk/jython/Lib/test/test_descr.py =================================================================== --- trunk/jython/Lib/test/test_descr.py 2007-08-31 05:38:47 UTC (rev 3460) +++ trunk/jython/Lib/test/test_descr.py 2007-08-31 21:46:13 UTC (rev 3461) @@ -3909,6 +3909,71 @@ except RuntimeError: pass +def subclass_binop(): + if verbose: + print "Testing binary ops with subclasses" + + def raises(exc, expected, callable, *args): + try: + callable(*args) + except exc, msg: + if str(msg) != expected: + raise TestFailed, "Message %r, expected %r" % (str(msg), + expected) + else: + raise TestFailed, "Expected %s" % exc + + class B(object): + pass + + class C(object): + def __radd__(self, o): + return '%r + C()' % (o,) + + def __rmul__(self, o): + return '%r * C()' % (o,) + + # Test strs, unicode, lists and tuples + mapping = [] + + # + binop + mapping.append((lambda o: 'foo' + o, + TypeError, "cannot concatenate 'str' and 'B' objects", + "'foo' + C()")) + # XXX: There's probably work to be done here besides just emulating this + # message + #mapping.append((lambda o: u'foo' + o, + # TypeError, + # 'coercing to Unicode: need string or buffer, B found', + # "u'foo' + C()")) + mapping.append((lambda o: u'foo' + o, + TypeError, "cannot concatenate 'unicode' and 'B' objects", + "u'foo' + C()")) + mapping.append((lambda o: [1, 2] + o, + TypeError, 'can only concatenate list (not "B") to list', + '[1, 2] + C()')) + mapping.append((lambda o: ('foo', 'bar') + o, + TypeError, 'can only concatenate tuple (not "B") to tuple', + "('foo', 'bar') + C()")) + + # * binop + mapping.append((lambda o: 'foo' * o, + TypeError, "can't multiply sequence by non-int of type 'B'", + "'foo' * C()")) + mapping.append((lambda o: u'foo' * o, + TypeError, "can't multiply sequence by non-int of type 'B'", + "u'foo' * C()")) + mapping.append((lambda o: [1, 2] * o, + TypeError, "can't multiply sequence by non-int of type 'B'", + '[1, 2] * C()')) + mapping.append((lambda o: ('foo', 'bar') * o, + TypeError, "can't multiply sequence by non-int of type 'B'", + "('foo', 'bar') * C()")) + + for func, bexc, bexc_msg, cresult in mapping: + raises(bexc, bexc_msg, lambda : func(B())) + vereq(func(C()), cresult) + def test_main(): testfuncs = [ weakref_segfault, # Must be first, somehow @@ -3998,6 +4063,7 @@ proxysuper, carloverre, filefault, + subclass_binop, ] if __name__ == '__main__': import sys Modified: trunk/jython/src/org/python/core/PyList.java =================================================================== --- trunk/jython/src/org/python/core/PyList.java 2007-08-31 05:38:47 UTC (rev 3460) +++ trunk/jython/src/org/python/core/PyList.java 2007-08-31 21:46:13 UTC (rev 3461) @@ -282,6 +282,82 @@ } dict.__setitem__("__setslice__",new PyMethodDescr("__setslice__",PyList.class,3,4,new exposed___setslice__(null,null))); + class exposed___add__ extends PyBuiltinMethodNarrow { + + exposed___add__(PyObject self,PyBuiltinFunction.Info info) { + super(self,info); + } + + public PyBuiltinFunction bind(PyObject self) { + return new exposed___add__(self,info); + } + + public PyObject __call__(PyObject arg0) { + PyObject ret=((PyList)self).list___add__(arg0); + if (ret==null) + return Py.NotImplemented; + return ret; + } + + } + dict.__setitem__("__add__",new PyMethodDescr("__add__",PyList.class,1,1,new exposed___add__(null,null))); + class exposed___radd__ extends PyBuiltinMethodNarrow { + + exposed___radd__(PyObject self,PyBuiltinFunction.Info info) { + super(self,info); + } + + public PyBuiltinFunction bind(PyObject self) { + return new exposed___radd__(self,info); + } + + public PyObject __call__(PyObject arg0) { + PyObject ret=((PyList)self).list___radd__(arg0); + if (ret==null) + return Py.NotImplemented; + return ret; + } + + } + dict.__setitem__("__radd__",new PyMethodDescr("__radd__",PyList.class,1,1,new exposed___radd__(null,null))); + class exposed___mul__ extends PyBuiltinMethodNarrow { + + exposed___mul__(PyObject self,PyBuiltinFunction.Info info) { + super(self,info); + } + + public PyBuiltinFunction bind(PyObject self) { + return new exposed___mul__(self,info); + } + + public PyObject __call__(PyObject arg0) { + PyObject ret=((PyList)self).list___mul__(arg0); + if (ret==null) + return Py.NotImplemented; + return ret; + } + + } + dict.__setitem__("__mul__",new PyMethodDescr("__mul__",PyList.class,1,1,new exposed___mul__(null,null))); + class exposed___rmul__ extends PyBuiltinMethodNarrow { + + exposed___rmul__(PyObject self,PyBuiltinFunction.Info info) { + super(self,info); + } + + public PyBuiltinFunction bind(PyObject self) { + return new exposed___rmul__(self,info); + } + + public PyObject __call__(PyObject arg0) { + PyObject ret=((PyList)self).list___rmul__(arg0); + if (ret==null) + return Py.NotImplemented; + return ret; + } + + } + dict.__setitem__("__rmul__",new PyMethodDescr("__rmul__",PyList.class,1,1,new exposed___rmul__(null,null))); class exposed_append extends PyBuiltinMethodNarrow { exposed_append(PyObject self,PyBuiltinFunction.Info info) { @@ -514,38 +590,6 @@ } dict.__setitem__("__len__",new PyMethodDescr("__len__",PyList.class,0,0,new exposed___len__(null,null))); - class exposed___add__ extends PyBuiltinMethodNarrow { - - exposed___add__(PyObject self,PyBuiltinFunction.Info info) { - super(self,info); - } - - public PyBuiltinFunction bind(PyObject self) { - return new exposed___add__(self,info); - } - - public PyObject __call__(PyObject arg0) { - return((PyList)self).list___add__(arg0); - } - - } - dict.__setitem__("__add__",new PyMethodDescr("__add__",PyList.class,1,1,new exposed___add__(null,null))); - class exposed___radd__ extends PyBuiltinMethodNarrow { - - exposed___radd__(PyObject self,PyBuiltinFunction.Info info) { - super(self,info); - } - - public PyBuiltinFunction bind(PyObject self) { - return new exposed___radd__(self,info); - } - - public PyObject __call__(PyObject arg0) { - return((PyList)self).list___radd__(arg0); - } - - } - dict.__setitem__("__radd__",new PyMethodDescr("__radd__",PyList.class,1,1,new exposed___radd__(null,null))); class exposed___iadd__ extends PyBuiltinMethodNarrow { exposed___iadd__(PyObject self,PyBuiltinFunction.Info info) { @@ -578,38 +622,6 @@ } dict.__setitem__("__imul__",new PyMethodDescr("__imul__",PyList.class,1,1,new exposed___imul__(null,null))); - class exposed___mul__ extends PyBuiltinMethodNarrow { - - exposed___mul__(PyObject self,PyBuiltinFunction.Info info) { - super(self,info); - } - - public PyBuiltinFunction bind(PyObject self) { - return new exposed___mul__(self,info); - } - - public PyObject __call__(PyObject arg0) { - return((PyList)self).list___mul__(arg0); - } - - } - dict.__setitem__("__mul__",new PyMethodDescr("__mul__",PyList.class,1,1,new exposed___mul__(null,null))); - class exposed___rmul__ extends PyBuiltinMethodNarrow { - - exposed___rmul__(PyObject self,PyBuiltinFunction.Info info) { - super(self,info); - } - - public PyBuiltinFunction bind(PyObject self) { - return new exposed___rmul__(self,info); - } - - public PyObject __call__(PyObject arg0) { - return((PyList)self).list___rmul__(arg0); - } - - } - dict.__setitem__("__rmul__",new PyMethodDescr("__rmul__",PyList.class,1,1,new exposed___rmul__(null,null))); class exposed___hash__ extends PyBuiltinMethodNarrow { exposed___hash__(PyObject self,PyBuiltinFunction.Info info) { @@ -902,26 +914,23 @@ } public PyObject __imul__(PyObject o) { - try { - return list___imul__(o); - } catch(PyException e) { - if(Py.matchException(e, Py.TypeError)) { - // We can't perform an in-place multiplication on o's type, so - // let o try to rmul this list. A new list will be created - // instead of modifying this one, but that's preferable to just - // blowing up on this operation. - PyObject result = o.__rmul__(this); - if(result != null) { - return result; - } + PyObject result = list___imul__(o); + if (result == null) { + // We can't perform an in-place multiplication on o's + // type, so let o try to rmul this list. A new list will + // be created instead of modifying this one, but that's + // preferable to just blowing up on this operation. + result = o.__rmul__(this); + if (result == null) { + throw Py.TypeError(_unsupportedop("*", o)); } - throw e; } + return result; } final PyObject list___imul__(PyObject o) { if (!(o instanceof PyInteger || o instanceof PyLong)) - throw Py.TypeError("can't multiply sequence to non-int"); + return null; int l = size(); int count = ((PyInteger)o.__int__()).getValue(); @@ -937,14 +946,14 @@ final PyObject list___mul__(PyObject o) { if (!(o instanceof PyInteger || o instanceof PyLong)) - throw Py.TypeError("can't multiply sequence to non-int"); + return null; int count = ((PyInteger)o.__int__()).getValue(); return repeat(count); } final PyObject list___rmul__(PyObject o) { if (!(o instanceof PyInteger || o instanceof PyLong)) - throw Py.TypeError("can't multiply sequence to non-int"); + return null; int count = ((PyInteger)o.__int__()).getValue(); return repeat(count); } @@ -1002,15 +1011,8 @@ if (op.equals("+")) { return "can only concatenate list (not \"{2}\") to list"; } - return null; + return super.unsupportedopMessage(op, o2); } - - protected String runsupportedopMessage(String op, PyObject o2) { - if (op.equals("+")) { - return "can only concatenate list (not \"{1}\") to list"; - } - return null; - } public String toString() { return list_toString(); Modified: trunk/jython/src/org/python/core/PySequence.java =================================================================== --- trunk/jython/src/org/python/core/PySequence.java 2007-08-31 05:38:47 UTC (rev 3460) +++ trunk/jython/src/org/python/core/PySequence.java 2007-08-31 21:46:13 UTC (rev 3461) @@ -474,4 +474,32 @@ } return super.__tojava__(c); } + + /** + * Return sequence-specific error messages suitable for substitution. + * + * {0} is the op name. + * {1} is the left operand type. + * {2} is the right operand type. + */ + protected String unsupportedopMessage(String op, PyObject o2) { + if (op.equals("*")) { + return "can''t multiply sequence by non-int of type ''{2}''"; + } + return null; + } + + /** + * Return sequence-specific error messages suitable for substitution. + * + * {0} is the op name. + * {1} is the left operand type. + * {2} is the right operand type. + */ + protected String runsupportedopMessage(String op, PyObject o2) { + if (op.equals("*")) { + return "can''t multiply sequence by non-int of type ''{1}''"; + } + return null; + } } Modified: trunk/jython/src/org/python/core/PyString.java =================================================================== --- trunk/jython/src/org/python/core/PyString.java 2007-08-31 05:38:47 UTC (rev 3460) +++ trunk/jython/src/org/python/core/PyString.java 2007-08-31 21:46:13 UTC (rev 3461) @@ -126,142 +126,154 @@ } dict.__setitem__("__ge__",new PyMethodDescr("__ge__",PyString.class,1,1,new exposed___ge__(null,null))); - class exposed___getitem__ extends PyBuiltinMethodNarrow { + class exposed___add__ extends PyBuiltinMethodNarrow { - exposed___getitem__(PyObject self,PyBuiltinFunction.Info info) { + exposed___add__(PyObject self,PyBuiltinFunction.Info info) { super(self,info); } public PyBuiltinFunction bind(PyObject self) { - return new exposed___getitem__(self,info); + return new exposed___add__(self,info); } public PyObject __call__(PyObject arg0) { - PyObject ret=((PyString)self).seq___finditem__(arg0); - if (ret==null) { - throw Py.IndexError("index out of range: "+arg0); - } + PyObject ret=((PyString)self).str___add__(arg0); + if (ret==null) + return Py.NotImplemented; return ret; } } - dict.__setitem__("__getitem__",new PyMethodDescr("__getitem__",PyString.class,1,1,new exposed___getitem__(null,null))); - class exposed___getslice__ extends PyBuiltinMethodNarrow { + dict.__setitem__("__add__",new PyMethodDescr("__add__",PyString.class,1,1,new exposed___add__(null,null))); + class exposed___mod__ extends PyBuiltinMethodNarrow { - exposed___getslice__(PyObject self,PyBuiltinFunction.Info info) { + exposed___mod__(PyObject self,PyBuiltinFunction.Info info) { super(self,info); } public PyBuiltinFunction bind(PyObject self) { - return new exposed___getslice__(self,info); + return new exposed___mod__(self,info); } - public PyObject __call__(PyObject arg0,PyObject arg1,PyObject arg2) { - return((PyString)self).seq___getslice__(arg0,arg1,arg2); + public PyObject __call__(PyObject arg0) { + PyObject ret=((PyString)self).str___mod__(arg0); + if (ret==null) + return Py.NotImplemented; + return ret; } - public PyObject __call__(PyObject arg0,PyObject arg1) { - return((PyString)self).seq___getslice__(arg0,arg1); - } - } - dict.__setitem__("__getslice__",new PyMethodDescr("__getslice__",PyString.class,2,3,new exposed___getslice__(null,null))); - class exposed___contains__ extends PyBuiltinMethodNarrow { + dict.__setitem__("__mod__",new PyMethodDescr("__mod__",PyString.class,1,1,new exposed___mod__(null,null))); + class exposed___mul__ extends PyBuiltinMethodNarrow { - exposed___contains__(PyObject self,PyBuiltinFunction.Info info) { + exposed___mul__(PyObject self,PyBuiltinFunction.Info info) { super(self,info); } public PyBuiltinFunction bind(PyObject self) { - return new exposed___contains__(self,info); + return new exposed___mul__(self,info); } public PyObject __call__(PyObject arg0) { - return Py.newBoolean(((PyString)self).str___contains__(arg0)); + PyObject ret=((PyString)self).str___mul__(arg0); + if (ret==null) + return Py.NotImplemented; + return ret; } } - dict.__setitem__("__contains__",new PyMethodDescr("__contains__",PyString.class,1,1,new exposed___contains__(null,null))); - class exposed___len__ extends PyBuiltinMethodNarrow { + dict.__setitem__("__mul__",new PyMethodDescr("__mul__",PyString.class,1,1,new exposed___mul__(null,null))); + class exposed___rmul__ extends PyBuiltinMethodNarrow { - exposed___len__(PyObject self,PyBuiltinFunction.Info info) { + exposed___rmul__(PyObject self,PyBuiltinFunction.Info info) { super(self,info); } public PyBuiltinFunction bind(PyObject self) { - return new exposed___len__(self,info); + return new exposed___rmul__(self,info); } - public PyObject __call__() { - return Py.newInteger(((PyString)self).str___len__()); + public PyObject __call__(PyObject arg0) { + PyObject ret=((PyString)self).str___rmul__(arg0); + if (ret==null) + return Py.NotImplemented; + return ret; } } - dict.__setitem__("__len__",new PyMethodDescr("__len__",PyString.class,0,0,new exposed___len__(null,null))); - class exposed___add__ extends PyBuiltinMethodNarrow { + dict.__setitem__("__rmul__",new PyMethodDescr("__rmul__",PyString.class,1,1,new exposed___rmul__(null,null))); + class exposed___getitem__ extends PyBuiltinMethodNarrow { - exposed___add__(PyObject self,PyBuiltinFunction.Info info) { + exposed___getitem__(PyObject self,PyBuiltinFunction.Info info) { super(self,info); } public PyBuiltinFunction bind(PyObject self) { - return new exposed___add__(self,info); + return new exposed___getitem__(self,info); } public PyObject __call__(PyObject arg0) { - return((PyString)self).str___add__(arg0); + PyObject ret=((PyString)self).seq___finditem__(arg0); + if (ret==null) { + throw Py.IndexError("index out of range: "+arg0); + } + return ret; } } - dict.__setitem__("__add__",new PyMethodDescr("__add__",PyString.class,1,1,new exposed___add__(null,null))); - class exposed___mod__ extends PyBuiltinMethodNarrow { + dict.__setitem__("__getitem__",new PyMethodDescr("__getitem__",PyString.class,1,1,new exposed___getitem__(null,null))); + class exposed___getslice__ extends PyBuiltinMethodNarrow { - exposed___mod__(PyObject self,PyBuiltinFunction.Info info) { + exposed___getslice__(PyObject self,PyBuiltinFunction.Info info) { super(self,info); } public PyBuiltinFunction bind(PyObject self) { - return new exposed___mod__(self,info); + return new exposed___getslice__(self,info); } - public PyObject __call__(PyObject arg0) { - return((PyString)self).str___mod__(arg0); + public PyObject __call__(PyObject arg0,PyObject arg1,PyObject arg2) { + return((PyString)self).seq___getslice__(arg0,arg1,arg2); } + public PyObject __call__(PyObject arg0,PyObject arg1) { + return((PyString)self).seq___getslice__(arg0,arg1); + } + } - dict.__setitem__("__mod__",new PyMethodDescr("__mod__",PyString.class,1,1,new exposed___mod__(null,null))); - class exposed___mul__ extends PyBuiltinMethodNarrow { + dict.__setitem__("__getslice__",new PyMethodDescr("__getslice__",PyString.class,2,3,new exposed___getslice__(null,null))); + class exposed___contains__ extends PyBuiltinMethodNarrow { - exposed___mul__(PyObject self,PyBuiltinFunction.Info info) { + exposed___contains__(PyObject self,PyBuiltinFunction.Info info) { super(self,info); } public PyBuiltinFunction bind(PyObject self) { - return new exposed___mul__(self,info); + return new exposed___contains__(self,info); } public PyObject __call__(PyObject arg0) { - return((PyString)self).str___mul__(arg0); + return Py.newBoolean(((PyString)self).str___contains__(arg0)); } } - dict.__setitem__("__mul__",new PyMethodDescr("__mul__",PyString.class,1,1,new exposed___mul__(null,null))); - class exposed___rmul__ extends PyBuiltinMethodNarrow { + dict.__setitem__("__contains__",new PyMethodDescr("__contains__",PyString.class,1,1,new exposed___contains__(null,null))); + class exposed___len__ extends PyBuiltinMethodNarrow { - exposed___rmul__(PyObject self,PyBuiltinFunction.Info info) { + exposed___len__(PyObject self,PyBuiltinFunction.Info info) { super(self,info); } public PyBuiltinFunction bind(PyObject self) { - return new exposed___rmul__(self,info); + return new exposed___len__(self,info); } - public PyObject __call__(PyObject arg0) { - return((PyString)self).str___rmul__(arg0); + public PyObject __call__() { + return Py.newInteger(((PyString)self).str___len__()); } } - dict.__setitem__("__rmul__",new PyMethodDescr("__rmul__",PyString.class,1,1,new exposed___rmul__(null,null))); + dict.__setitem__("__len__",new PyMethodDescr("__len__",PyString.class,0,0,new exposed___len__(null,null))); class exposed___str__ extends PyBuiltinMethodNarrow { exposed___str__(PyObject self,PyBuiltinFunction.Info info) { @@ -2182,14 +2194,14 @@ final PyObject str___mul__(PyObject o) { if (!(o instanceof PyInteger || o instanceof PyLong)) - throw Py.TypeError("can't multiply sequence to non-int"); + return null; int count = ((PyInteger)o.__int__()).getValue(); return repeat(count); } final PyObject str___rmul__(PyObject o) { if (!(o instanceof PyInteger || o instanceof PyLong)) - throw Py.TypeError("can't multiply sequence to non-int"); + return null; int count = ((PyInteger)o.__int__()).getValue(); return repeat(count); } @@ -3606,6 +3618,12 @@ return internedString(); } + protected String unsupportedopMessage(String op, PyObject o2) { + if (op.equals("+")) { + return "cannot concatenate ''{1}'' and ''{2}'' objects"; + } + return super.unsupportedopMessage(op, o2); + } } final class StringFormatter Modified: trunk/jython/src/org/python/core/PyTuple.java =================================================================== --- trunk/jython/src/org/python/core/PyTuple.java 2007-08-31 05:38:47 UTC (rev 3460) +++ trunk/jython/src/org/python/core/PyTuple.java 2007-08-31 21:46:13 UTC (rev 3461) @@ -139,126 +139,135 @@ } dict.__setitem__("__ge__",new PyMethodDescr("__ge__",PyTuple.class,1,1,new exposed___ge__(null,null))); - class exposed___getitem__ extends PyBuiltinMethodNarrow { + class exposed___add__ extends PyBuiltinMethodNarrow { - exposed___getitem__(PyObject self,PyBuiltinFunction.Info info) { + exposed___add__(PyObject self,PyBuiltinFunction.Info info) { super(self,info); } public PyBuiltinFunction bind(PyObject self) { - return new exposed___getitem__(self,info); + return new exposed___add__(self,info); } public PyObject __call__(PyObject arg0) { - PyObject ret=((PyTuple)self).seq___finditem__(arg0); - if (ret==null) { - throw Py.IndexError("index out of range: "+arg0); - } + PyObject ret=((PyTuple)self).tuple___add__(arg0); + if (ret==null) + return Py.NotImplemented; return ret; } } - dict.__setitem__("__getitem__",new PyMethodDescr("__getitem__",PyTuple.class,1,1,new exposed___getitem__(null,null))); - class exposed___getslice__ extends PyBuiltinMethodNarrow { + dict.__setitem__("__add__",new PyMethodDescr("__add__",PyTuple.class,1,1,new exposed___add__(null,null))); + class exposed___mul__ extends PyBuiltinMethodNarrow { - exposed___getslice__(PyObject self,PyBuiltinFunction.Info info) { + exposed___mul__(PyObject self,PyBuiltinFunction.Info info) { super(self,info); } public PyBuiltinFunction bind(PyObject self) { - return new exposed___getslice__(self,info); + return new exposed___mul__(self,info); } - public PyObject __call__(PyObject arg0,PyObject arg1,PyObject arg2) { - return((PyTuple)self).seq___getslice__(arg0,arg1,arg2); + public PyObject __call__(PyObject arg0) { + PyObject ret=((PyTuple)self).tuple___mul__(arg0); + if (ret==null) + return Py.NotImplemented; + return ret; } - public PyObject __call__(PyObject arg0,PyObject arg1) { - return((PyTuple)self).seq___getslice__(arg0,arg1); - } - } - dict.__setitem__("__getslice__",new PyMethodDescr("__getslice__",PyTuple.class,2,3,new exposed___getslice__(null,null))); - class exposed___contains__ extends PyBuiltinMethodNarrow { + dict.__setitem__("__mul__",new PyMethodDescr("__mul__",PyTuple.class,1,1,new exposed___mul__(null,null))); + class exposed___rmul__ extends PyBuiltinMethodNarrow { - exposed___contains__(PyObject self,PyBuiltinFunction.Info info) { + exposed___rmul__(PyObject self,PyBuiltinFunction.Info info) { super(self,info); } public PyBuiltinFunction bind(PyObject self) { - return new exposed___contains__(self,info); + return new exposed___rmul__(self,info); } public PyObject __call__(PyObject arg0) { - return Py.newBoolean(((PyTuple)self).tuple___contains__(arg0)); + PyObject ret=((PyTuple)self).tuple___rmul__(arg0); + if (ret==null) + return Py.NotImplemented; + return ret; } } - dict.__setitem__("__contains__",new PyMethodDescr("__contains__",PyTuple.class,1,1,new exposed___contains__(null,null))); - class exposed___len__ extends PyBuiltinMethodNarrow { + dict.__setitem__("__rmul__",new PyMethodDescr("__rmul__",PyTuple.class,1,1,new exposed___rmul__(null,null))); + class exposed___getitem__ extends PyBuiltinMethodNarrow { - exposed___len__(PyObject self,PyBuiltinFunction.Info info) { + exposed___getitem__(PyObject self,PyBuiltinFunction.Info info) { super(self,info); } public PyBuiltinFunction bind(PyObject self) { - return new exposed___len__(self,info); + return new exposed___getitem__(self,info); } - public PyObject __call__() { - return Py.newInteger(((PyTuple)self).tuple___len__()); + public PyObject __call__(PyObject arg0) { + PyObject ret=((PyTuple)self).seq___finditem__(arg0); + if (ret==null) { + throw Py.IndexError("index out of range: "+arg0); + } + return ret; } } - dict.__setitem__("__len__",new PyMethodDescr("__len__",PyTuple.class,0,0,new exposed___len__(null,null))); - class exposed___add__ extends PyBuiltinMethodNarrow { + dict.__setitem__("__getitem__",new PyMethodDescr("__getitem__",PyTuple.class,1,1,new exposed___getitem__(null,null))); + class exposed___getslice__ extends PyBuiltinMethodNarrow { - exposed___add__(PyObject self,PyBuiltinFunction.Info info) { + exposed___getslice__(PyObject self,PyBuiltinFunction.Info info) { super(self,info); } public PyBuiltinFunction bind(PyObject self) { - return new exposed___add__(self,info); + return new exposed___getslice__(self,info); } - public PyObject __call__(PyObject arg0) { - return((PyTuple)self).tuple___add__(arg0); + public PyObject __call__(PyObject arg0,PyObject arg1,PyObject arg2) { + return((PyTuple)self).seq___getslice__(arg0,arg1,arg2); } + public PyObject __call__(PyObject arg0,PyObject arg1) { + return((PyTuple)self).seq___getslice__(arg0,arg1); + } + } - dict.__setitem__("__add__",new PyMethodDescr("__add__",PyTuple.class,1,1,new exposed___add__(null,null))); - class exposed___mul__ extends PyBuiltinMethodNarrow { + dict.__setitem__("__getslice__",new PyMethodDescr("__getslice__",PyTuple.class,2,3,new exposed___getslice__(null,null))); + class exposed___contains__ extends PyBuiltinMethodNarrow { - exposed___mul__(PyObject self,PyBuiltinFunction.Info info) { + exposed___contains__(PyObject self,PyBuiltinFunction.Info info) { super(self,info); } public PyBuiltinFunction bind(PyObject self) { - return new exposed___mul__(self,info); + return new exposed___contains__(self,info); } public PyObject __call__(PyObject arg0) { - return((PyTuple)self).tuple___mul__(arg0); + return Py.newBoolean(((PyTuple)self).tuple___contains__(arg0)); } } - dict.__setitem__("__mul__",new PyMethodDescr("__mul__",PyTuple.class,1,1,new exposed___mul__(null,null))); - class exposed___rmul__ extends PyBuiltinMethodNarrow { + dict.__setitem__("__contains__",new PyMethodDescr("__contains__",PyTuple.class,1,1,new exposed___contains__(null,null))); + class exposed___len__ extends PyBuiltinMethodNarrow { - exposed___rmul__(PyObject self,PyBuiltinFunction.Info info) { + exposed___len__(PyObject self,PyBuiltinFunction.Info info) { super(self,info); } public PyBuiltinFunction bind(PyObject self) { - return new exposed___rmul__(self,info); + return new exposed___len__(self,info); } - public PyObject __call__(PyObject arg0) { - return((PyTuple)self).tuple___rmul__(arg0); + public PyObject __call__() { + return Py.newInteger(((PyTuple)self).tuple___len__()); } } - dict.__setitem__("__rmul__",new PyMethodDescr("__rmul__",PyTuple.class,1,1,new exposed___rmul__(null,null))); + dict.__setitem__("__len__",new PyMethodDescr("__len__",PyTuple.class,0,0,new exposed___len__(null,null))); class exposed___getnewargs__ extends PyBuiltinMethodNarrow { exposed___getnewargs__(PyObject self,PyBuiltinFunction.Info info) { @@ -463,14 +472,14 @@ final PyObject tuple___mul__(PyObject o) { if (!(o instanceof PyInteger || o instanceof PyLong)) - throw Py.TypeError("can't multiply sequence to non-int"); + return null; int count = ((PyInteger)o.__int__()).getValue(); return repeat(count); } final PyObject tuple___rmul__(PyObject o) { if (!(o instanceof PyInteger || o instanceof PyLong)) - throw Py.TypeError("can't multiply sequence to non-int"); + return null; int count = ((PyInteger)o.__int__()).getValue(); return repeat(count); } @@ -621,4 +630,11 @@ } }; } + + protected String unsupportedopMessage(String op, PyObject o2) { + if (op.equals("+")) { + return "can only concatenate tuple (not \"{2}\") to tuple"; + } + return super.unsupportedopMessage(op, o2); + } } Modified: trunk/jython/src/org/python/core/PyUnicode.java =================================================================== --- trunk/jython/src/org/python/core/PyUnicode.java 2007-08-31 05:38:47 UTC (rev 3460) +++ trunk/jython/src/org/python/core/PyUnicode.java 2007-08-31 21:46:13 UTC (rev 3461) @@ -53,126 +53,135 @@ } dict.__setitem__("__eq__",new PyMethodDescr("__eq__",PyUnicode.class,1,1,new exposed___eq__(null,null))); - class exposed___getitem__ extends PyBuiltinMethodNarrow { + class exposed___add__ extends PyBuiltinMethodNarrow { - exposed___getitem__(PyObject self,PyBuiltinFunction.Info info) { + exposed___add__(PyObject self,PyBuiltinFunction.Info info) { super(self,info); } public PyBuiltinFunction bind(PyObject self) { - return new exposed___getitem__(self,info); + return new exposed___add__(self,info); } public PyObject __call__(PyObject arg0) { - PyObject ret=((PyUnicode)self).seq___finditem__(arg0); - if (ret==null) { - throw Py.IndexError("index out of range: "+arg0); - } + PyObject ret=((PyUnicode)self).unicode___add__(arg0); + if (ret==null) + return Py.NotImplemented; return ret; } } - dict.__setitem__("__getitem__",new PyMethodDescr("__getitem__",PyUnicode.class,1,1,new exposed___getitem__(null,null))); - class exposed___getslice__ extends PyBuiltinMethodNarrow { + dict.__setitem__("__add__",new PyMethodDescr("__add__",PyUnicode.class,1,1,new exposed___add__(null,null))); + class exposed___mul__ extends PyBuiltinMethodNarrow { - exposed___getslice__(PyObject self,PyBuiltinFunction.Info info) { + exposed___mul__(PyObject self,PyBuiltinFunction.Info info) { super(self,info); } public PyBuiltinFunction bind(PyObject self) { - return new exposed___getslice__(self,info); + return new exposed___mul__(self,info); } - public PyObject __call__(PyObject arg0,PyObject arg1,PyObject arg2) { - return((PyUnicode)self).seq___getslice__(arg0,arg1,arg2); + public PyObject __call__(PyObject arg0) { + PyObject ret=((PyUnicode)self).unicode___mul__(arg0); + if (ret==null) + return Py.NotImplemented; + return ret; } - public PyObject __call__(PyObject arg0,PyObject arg1) { - return((PyUnicode)self).seq___getslice__(arg0,arg1); - } - } - dict.__setitem__("__getslice__",new PyMethodDescr("__getslice__",PyUnicode.class,2,3,new exposed___getslice__(null,null))); - class exposed___contains__ extends PyBuiltinMethodNarrow { + dict.__setitem__("__mul__",new PyMethodDescr("__mul__",PyUnicode.class,1,1,new exposed___mul__(null,null))); + class exposed___rmul__ extends PyBuiltinMethodNarrow { - exposed___contains__(PyObject self,PyBuiltinFunction.Info info) { + exposed___rmul__(PyObject self,PyBuiltinFunction.Info info) { super(self,info); } public PyBuiltinFunction bind(PyObject self) { - return new exposed___contains__(self,info); + return new exposed___rmul__(self,info); } public PyObject __call__(PyObject arg0) { - return Py.newBoolean(((PyUnicode)self).unicode___contains__(arg0)); + PyObject ret=((PyUnicode)self).unicode___rmul__(arg0); + if (ret==null) + return Py.NotImplemented; + return ret; } } - dict.__setitem__("__contains__",new PyMethodDescr("__contains__",PyUnicode.class,1,1,new exposed___contains__(null,null))); - class exposed___len__ extends PyBuiltinMethodNarrow { + dict.__setitem__("__rmul__",new PyMethodDescr("__rmul__",PyUnicode.class,1,1,new exposed___rmul__(null,null))); + class exposed___getitem__ extends PyBuiltinMethodNarrow { - exposed___len__(PyObject self,PyBuiltinFunction.Info info) { + exposed___getitem__(PyObject self,PyBuiltinFunction.Info info) { super(self,info); } public PyBuiltinFunction bind(PyObject self) { - return new exposed___len__(self,info); + return new exposed___getitem__(self,info); } - public PyObject __call__() { - return Py.newInteger(((PyUnicode)self).unicode___len__()); + public PyObject __call__(PyObject arg0) { + PyObject ret=((PyUnicode)self).seq___finditem__(arg0); + if (ret==null) { + throw Py.IndexError("index out of range: "+arg0); + } + return ret; } } - dict.__setitem__("__len__",new PyMethodDescr("__len__",PyUnicode.class,0,0,new exposed___len__(null,null))); - class exposed___add__ extends PyBuiltinMethodNarrow { + dict.__setitem__("__getitem__",new PyMethodDescr("__getitem__",PyUnicode.class,1,1,new exposed___getitem__(null,null))); + class exposed___getslice__ extends PyBuiltinMethodNarrow { - exposed___add__(PyObject self,PyBuiltinFunction.Info info) { + exposed___getslice__(PyObject self,PyBuiltinFunction.Info info) { super(self,info); } public PyBuiltinFunction bind(PyObject self) { - return new exposed___add__(self,info); + return new exposed___getslice__(self,info); } - public PyObject __call__(PyObject arg0) { - return((PyUnicode)self).unicode___add__(arg0); + public PyObject __call__(PyObject arg0,PyObject arg1,PyObject arg2) { + return((PyUnicode)self).seq___getslice__(arg0,arg1,arg2); } + public PyObject __call__(PyObject arg0,PyObject arg1) { + return((PyUnicode)self).seq___getslice__(arg0,arg1); + } + } - dict.__setitem__("__add__",new PyMethodDescr("__add__",PyUnicode.class,1,1,new exposed___add__(null,null))); - class exposed___mul__ extends PyBuiltinMethodNarrow { + dict.__setitem__("__getslice__",new PyMethodDescr("__getslice__",PyUnicode.class,2,3,new exposed___getslice__(null,null))); + class exposed___contains__ extends PyBuiltinMethodNarrow { - exposed___mul__(PyObject self,PyBuiltinFunction.Info info) { + exposed___contains__(PyObject self,PyBuiltinFunction.Info info) { super(self,info); } public PyBuiltinFunction bind(PyObject self) { - return new exposed___mul__(self,info); + return new exposed___contains__(self,info); } public PyObject __call__(PyObject arg0) { - return((PyUnicode)self).unicode___mul__(arg0); + return Py.newBoolean(((PyUnicode)self).unicode___contains__(arg0)); } } - dict.__setitem__("__mul__",new PyMethodDescr("__mul__",PyUnicode.class,1,1,new exposed___mul__(null,null))); - class exposed___rmul__ extends PyBuiltinMethodNarrow { + dict.__setitem__("__contains__",new PyMethodDescr("__contains__",PyUnicode.class,1,1,new exposed___contains__(null,null))); + class exposed___len__ extends PyBuiltinMethodNarrow { - exposed___rmul__(PyObject self,PyBuiltinFunction.Info info) { + exposed___len__(PyObject self,PyBuiltinFunction.Info info) { super(self,info); } public PyBuiltinFunction bind(PyObject self) { - return new exposed___rmul__(self,info); + return new exposed___len__(self,info); } - public PyObject __call__(PyObject arg0) { - return((PyUnicode)self).unicode___rmul__(arg0); + public PyObject __call__() { + return Py.newInteger(((PyUnicode)self).unicode___len__()); } } - dict.__setitem__("__rmul__",new PyMethodDescr("__rmul__",PyUnicode.class,1,1,new exposed___rmul__(null,null))); + dict.__setitem__("__len__",new PyMethodDescr("__len__",PyUnicode.class,0,0,new exposed___len__(null,null))); class exposed___str__ extends PyBuiltinMethodNarrow { exposed___str__(PyObject self,PyBuiltinFunction.Info info) { Modified: trunk/jython/src/templates/list.expose =================================================================== --- trunk/jython/src/templates/list.expose 2007-08-31 05:38:47 UTC (rev 3460) +++ trunk/jython/src/templates/list.expose 2007-08-31 21:46:13 UTC (rev 3461) @@ -5,6 +5,7 @@ incl: sequence #expose_meth: seq_> __iter__ # exposed methods +expose_binary: __add__ __radd__ __mul__ __rmul__ expose_meth: :- append o expose_meth: :i count o expose_meth: :- extend o @@ -15,12 +16,8 @@ expose_meth: :- reverse expose_meth: :- sort o? expose_meth: :i __len__ -expose_meth: __add__ o -expose_meth: __radd__ o expose_meth: __iadd__ o expose_meth: __imul__ o -expose_meth: __mul__ o -expose_meth: __rmul__ o expose_meth: __hash__ `ideleg`(hashCode); expose_meth: __repr__ Modified: trunk/jython/src/templates/str.expose =================================================================== --- trunk/jython/src/templates/str.expose 2007-08-31 05:38:47 UTC (rev 3460) +++ trunk/jython/src/templates/str.expose 2007-08-31 21:46:13 UTC (rev 3461) @@ -5,13 +5,10 @@ expose_index_getitem: seq_> expose_meth: seq_> __getslice__ ooo? # -expose_binary: __ne__ __eq__ __lt__ __le__ __gt__ __ge__ +expose_binary: __ne__ __eq__ __lt__ __le__ __gt__ __ge__ __add__ __mod__ \ + __mul__ __rmul__ expose_meth: :b __contains__ o expose_meth: :i __len__ -expose_meth: __add__ o -expose_meth: __mod__ o -expose_meth: __mul__ o -expose_meth: __rmul__ o expose_meth: __str__ expose_meth: __unicode__ expose_meth: __hash__ Modified: trunk/jython/src/templates/tuple.expose =================================================================== --- trunk/jython/src/templates/tuple.expose 2007-08-31 05:38:47 UTC (rev 3460) +++ trunk/jython/src/templates/tuple.expose 2007-08-31 21:46:13 UTC (rev 3461) @@ -7,12 +7,10 @@ expose_meth: seq_> __getslice__ ooo? #expose_meth: seq_> __iter__ # -expose_binary: __ne__ __eq__ __lt__ __le__ __gt__ __ge__ +expose_binary: __ne__ __eq__ __lt__ __le__ __gt__ __ge__ __add__ __mul__ \ + __rmul__ expose_meth: :b __contains__ o expose_meth: :i __len__ -expose_meth: __add__ o -expose_meth: __mul__ o -expose_meth: __rmul__ o expose_meth: __getnewargs__ expose_meth: __hash__ `ideleg`(hashCode); Modified: trunk/jython/src/templates/unicode.expose =================================================================== --- trunk/jython/src/templates/unicode.expose 2007-08-31 05:38:47 UTC (rev 3460) +++ trunk/jython/src/templates/unicode.expose 2007-08-31 21:46:13 UTC (rev 3461) @@ -5,12 +5,9 @@ expose_index_getitem: seq_> expose_meth: seq_> __getslice__ ooo? # -expose_binary: __ne__ __eq__ +expose_binary: __ne__ __eq__ __add__ __mul__ __rmul__ expose_meth: :b __contains__ o expose_meth: :i __len__ -expose_meth: __add__ o -expose_meth: __mul__ o -expose_meth: __rmul__ o expose_meth: __str__ expose_meth: __unicode__ expose_meth: __hash__ This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <fwi...@us...> - 2007-09-06 15:48:08
|
Revision: 3470 http://jython.svn.sourceforge.net/jython/?rev=3470&view=rev Author: fwierzbicki Date: 2007-09-06 08:47:53 -0700 (Thu, 06 Sep 2007) Log Message: ----------- Added pop() to stringmap. Thanks to Brian Rosner for some code for the two arg pop(). I needed to modify that code a bit to better conform to the MappingProtocol (those tests are in the new test_stringmap.py) Modified Paths: -------------- trunk/jython/src/org/python/core/PyStringMap.java Added Paths: ----------- trunk/jython/Lib/test/test_stringmap.py Added: trunk/jython/Lib/test/test_stringmap.py =================================================================== --- trunk/jython/Lib/test/test_stringmap.py (rev 0) +++ trunk/jython/Lib/test/test_stringmap.py 2007-09-06 15:47:53 UTC (rev 3470) @@ -0,0 +1,36 @@ +import unittest +from test import test_support + +from test_userdict import TestMappingProtocol + +class SimpleClass: + pass + +class ClassDictTests(TestMappingProtocol): + """check that os.environ object conform to mapping protocol""" + _tested_class = None + def _reference(self): + return {"key1":"value1", "key2":2, "key3":(1,2,3)} + #return {"KEY1":"VALUE1", "KEY2":"VALUE2", "KEY3":"VALUE3"} + def _empty_mapping(self): + for key in SimpleClass.__dict__: + SimpleClass.__dict__.pop(key) + return SimpleClass.__dict__ + +class InstanceDictTests(TestMappingProtocol): + """check that os.environ object conform to mapping protocol""" + _tested_class = None + def _reference(self): + return {"key1":"value1", "key2":2, "key3":(1,2,3)} + #return {"KEY1":"VALUE1", "KEY2":"VALUE2", "KEY3":"VALUE3"} + def _empty_mapping(self): + return SimpleClass().__dict__ + +def test_main(): + test_support.run_unittest( + ClassDictTests, + InstanceDictTests, + ) + +if __name__ == "__main__": + test_main() Modified: trunk/jython/src/org/python/core/PyStringMap.java =================================================================== --- trunk/jython/src/org/python/core/PyStringMap.java 2007-09-03 22:59:11 UTC (rev 3469) +++ trunk/jython/src/org/python/core/PyStringMap.java 2007-09-06 15:47:53 UTC (rev 3470) @@ -581,6 +581,25 @@ public synchronized PyObject itervalues() { return new PyStringMapIter(keys, values, PyStringMapIter.VALUES); } + + public synchronized PyObject pop(PyObject key) { + if (size == 0) + throw Py.KeyError("pop(): dictionary is empty"); + return pop(key, null); + } + + public synchronized PyObject pop(PyObject key, PyObject failobj) { + PyObject value = __finditem__(key); + if(value == null) { + if (failobj == null) { + throw Py.KeyError(key.__repr__().toString()); + } else { + return failobj; + } + } + __delitem__(key); + return value; + } } /* extended, based on PyDictionaryIter */ This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <pj...@us...> - 2007-09-13 01:11:35
|
Revision: 3472 http://jython.svn.sourceforge.net/jython/?rev=3472&view=rev Author: pjenvey Date: 2007-09-12 18:11:26 -0700 (Wed, 12 Sep 2007) Log Message: ----------- s/jpython/jython/g in Lib, Tools and src dirs, except in a few places when referring to historical JPython versions Modified Paths: -------------- trunk/jython/Lib/doctest.py trunk/jython/Lib/pawt/swing.py trunk/jython/Lib/test/bugs/pr195.py trunk/jython/Lib/test/bugs/pr235.py trunk/jython/Lib/test/test_jbasic.py trunk/jython/Tools/freeze/Output.py trunk/jython/Tools/freeze/freeze.py trunk/jython/Tools/jythonc/ObjectFactory.py trunk/jython/Tools/jythonc/PythonModule.py trunk/jython/Tools/jythonc/compile.py trunk/jython/Tools/jythonc/jar.py trunk/jython/Tools/jythonc/jast/Output.py trunk/jython/Tools/jythonc/javac.py trunk/jython/Tools/jythonc/jythonc.py trunk/jython/Tools/jythonc/main.py trunk/jython/Tools/mkjava.py trunk/jython/src/org/python/core/Options.java trunk/jython/src/org/python/core/PyFile.java trunk/jython/src/org/python/core/PyFunction.java trunk/jython/src/org/python/core/PySystemState.java trunk/jython/src/org/python/core/PyTableCode.java trunk/jython/src/org/python/modules/MD5Module.java trunk/jython/src/org/python/modules/Setup.java trunk/jython/src/org/python/modules/imp.java trunk/jython/src/org/python/modules/time/Time.java trunk/jython/src/org/python/util/InteractiveInterpreter.java trunk/jython/src/org/python/util/PyServlet.java trunk/jython/src/org/python/util/PythonInterpreter.java Modified: trunk/jython/Lib/doctest.py =================================================================== --- trunk/jython/Lib/doctest.py 2007-09-13 00:21:35 UTC (rev 3471) +++ trunk/jython/Lib/doctest.py 2007-09-13 01:11:26 UTC (rev 3472) @@ -401,7 +401,7 @@ if hasattr(self, "softspace"): del self.softspace def flush(self): - # JPython calls flush + # Jython calls flush pass # Display some tag-and-msg pairs nicely, keeping the tag and its msg Modified: trunk/jython/Lib/pawt/swing.py =================================================================== --- trunk/jython/Lib/pawt/swing.py 2007-09-13 00:21:35 UTC (rev 3471) +++ trunk/jython/Lib/pawt/swing.py 2007-09-13 01:11:26 UTC (rev 3472) @@ -37,6 +37,6 @@ sys.modules['pawt.swing'] = swing swing.__dict__['test'] = test - #These two lines help out jpythonc to figure out this very strange module + #These two lines help out jythonc to figure out this very strange module swing.__dict__['__file__'] = __file__ swing.__dict__['__jpythonc_name__'] = 'pawt.swing' Modified: trunk/jython/Lib/test/bugs/pr195.py =================================================================== --- trunk/jython/Lib/test/bugs/pr195.py 2007-09-13 00:21:35 UTC (rev 3471) +++ trunk/jython/Lib/test/bugs/pr195.py 2007-09-13 01:11:26 UTC (rev 3472) @@ -3,7 +3,7 @@ from javax.swing import AbstractListModel, ComboBoxModel # Note that AbstractListModel implements ListModel, ComboBoxModel extends -# ListModel. This would cause JPython to include +# ListModel. This would cause Jython to include # (Object)ListModel.getElementAt(int) twice in the proxy class, which is # illegal. Modified: trunk/jython/Lib/test/bugs/pr235.py =================================================================== --- trunk/jython/Lib/test/bugs/pr235.py 2007-09-13 00:21:35 UTC (rev 3471) +++ trunk/jython/Lib/test/bugs/pr235.py 2007-09-13 01:11:26 UTC (rev 3472) @@ -1,4 +1,4 @@ -# PR#235, JPython crashes (i.e. uncaught Java exception) under strange +# PR#235, Jython crashes (i.e. uncaught Java exception) under strange # (illegal) input. bogus = '''\ Modified: trunk/jython/Lib/test/test_jbasic.py =================================================================== --- trunk/jython/Lib/test/test_jbasic.py 2007-09-13 00:21:35 UTC (rev 3471) +++ trunk/jython/Lib/test/test_jbasic.py 2007-09-13 01:11:26 UTC (rev 3472) @@ -110,4 +110,4 @@ b1.doClick() assert flag == 1, 'one actions per event - again' -# TBD: JPython does not properly exit after this code! +# TBD: Jython does not properly exit after this code! Modified: trunk/jython/Tools/freeze/Output.py =================================================================== --- trunk/jython/Tools/freeze/Output.py 2007-09-13 00:21:35 UTC (rev 3471) +++ trunk/jython/Tools/freeze/Output.py 2007-09-13 01:11:26 UTC (rev 3472) @@ -84,9 +84,9 @@ pass if __name__ == '__main__': - for of in [CabOutput('c:\\jpython\\test.cab')]: #DirectoryOutput('c:\\jpython\\dtest'), ZipOutput('c:\\jpython\\test.jar')]: - of.write('org.python.core.PyInteger', 'c:\\jpython\\JavaCode\\org\\python\\core\\PyInteger.class') - of.write('org.python.core.PyFloat', 'c:\\jpython\\JavaCode\\org\\python\\core\\PyFloat.class') + for of in [CabOutput('c:\\jython\\test.cab')]: #DirectoryOutput('c:\\jython\\dtest'), ZipOutput('c:\\jython\\test.jar')]: + of.write('org.python.core.PyInteger', 'c:\\jython\\JavaCode\\org\\python\\core\\PyInteger.class') + of.write('org.python.core.PyFloat', 'c:\\jython\\JavaCode\\org\\python\\core\\PyFloat.class') bytes = ByteArrayOutputStream() bytes.write(jarray.array([10]*500, 'b')) of.write('hi.there', bytes) Modified: trunk/jython/Tools/freeze/freeze.py =================================================================== --- trunk/jython/Tools/freeze/freeze.py 2007-09-13 00:21:35 UTC (rev 3471) +++ trunk/jython/Tools/freeze/freeze.py 2007-09-13 01:11:26 UTC (rev 3472) @@ -108,7 +108,7 @@ f.finish(opts.main) if opts.core: - skiplist = ['org.python.core.parser', 'org.python.core.BytecodeLoader', 'org.python.core.jpython'] + skiplist = ['org.python.core.parser', 'org.python.core.BytecodeLoader', 'org.python.core.jython'] f.addPackage(os.path.join(sys.prefix, 'JavaCode', 'org', 'python', 'core'), skiplist) f.out.close() Modified: trunk/jython/Tools/jythonc/ObjectFactory.py =================================================================== --- trunk/jython/Tools/jythonc/ObjectFactory.py 2007-09-13 00:21:35 UTC (rev 3471) +++ trunk/jython/Tools/jythonc/ObjectFactory.py 2007-09-13 01:11:26 UTC (rev 3472) @@ -334,4 +334,4 @@ print mod.attributes.keys() print mod.imports.keys() print mod - mod.dump("c:\\jpython\\tools\\jpythonc2\\test") + mod.dump("c:\\jython\\tools\\jythonc2\\test") Modified: trunk/jython/Tools/jythonc/PythonModule.py =================================================================== --- trunk/jython/Tools/jythonc/PythonModule.py 2007-09-13 00:21:35 UTC (rev 3471) +++ trunk/jython/Tools/jythonc/PythonModule.py 2007-09-13 01:11:26 UTC (rev 3472) @@ -14,7 +14,7 @@ """ class foo - class py -- what gets imported by jpython + class py -- what gets imported by jython holds all py constants One of these no matter how many classes maybe have static inner classes as well @@ -478,4 +478,4 @@ pm.packages = ['java.lang', 'java.awt'] pm.getIntegerConstant(22) pm.getStringConstant("hello world") - pm.dump("c:\\jpython\\tools\\jpythonc2") + pm.dump("c:\\jython\\tools\\jythonc2") Modified: trunk/jython/Tools/jythonc/compile.py =================================================================== --- trunk/jython/Tools/jythonc/compile.py 2007-09-13 00:21:35 UTC (rev 3471) +++ trunk/jython/Tools/jythonc/compile.py 2007-09-13 01:11:26 UTC (rev 3472) @@ -480,5 +480,5 @@ ja = JavaArchive([('org.python.core', []),]) for jc in javaclasses: ja.addClass(outdir, jc) - outjar = "c:\\jpython\\tools\\jpythonc2\\test\\t.jar" + outjar = "c:\\jython\\tools\\jythonc2\\test\\t.jar" ja.dump(outjar) Modified: trunk/jython/Tools/jythonc/jar.py =================================================================== --- trunk/jython/Tools/jythonc/jar.py 2007-09-13 00:21:35 UTC (rev 3471) +++ trunk/jython/Tools/jythonc/jar.py 2007-09-13 01:11:26 UTC (rev 3472) @@ -165,7 +165,7 @@ if __name__ == '__main__': - root = "c:\\jpython\\tools\\jpythonc2" + root = "c:\\jython\\tools\\jythonc2" ja = JavaArchive() ja.addFile(root, "jar.py") ja.addFile(root, "proxies.py") Modified: trunk/jython/Tools/jythonc/jast/Output.py =================================================================== --- trunk/jython/Tools/jythonc/jast/Output.py 2007-09-13 00:21:35 UTC (rev 3471) +++ trunk/jython/Tools/jythonc/jast/Output.py 2007-09-13 01:11:26 UTC (rev 3472) @@ -13,7 +13,7 @@ self.classname = classname self.filename = classname+'.java' - def dump(self, directory="c:\\jpython\\test\\comp"): + def dump(self, directory="c:\\jython\\test\\comp"): fp = open(os.path.join(directory, self.filename), 'w') for bit in self.text: fp.write(bit) Modified: trunk/jython/Tools/jythonc/javac.py =================================================================== --- trunk/jython/Tools/jythonc/javac.py 2007-09-13 00:21:35 UTC (rev 3471) +++ trunk/jython/Tools/jythonc/javac.py 2007-09-13 01:11:26 UTC (rev 3472) @@ -109,8 +109,8 @@ if __name__ == '__main__': - files = ["c:\\jpython\\tools\\jpythonc2\\test\\ButtonDemo.java", - "c:\\jpython\\tools\\jpythonc2\\test\\pawt.java",] + files = ["c:\\jython\\tools\\jythonc2\\test\\ButtonDemo.java", + "c:\\jython\\tools\\jythonc2\\test\\pawt.java",] print compile(files) print compile(files, ["-foo", "bar"]) Modified: trunk/jython/Tools/jythonc/jythonc.py =================================================================== --- trunk/jython/Tools/jythonc/jythonc.py 2007-09-13 00:21:35 UTC (rev 3471) +++ trunk/jython/Tools/jythonc/jythonc.py 2007-09-13 01:11:26 UTC (rev 3472) @@ -1,6 +1,6 @@ # Copyright (c) Corporation for National Research Initiatives -# Driver script for jpythonc2. See module main.py for details +# Driver script for jythonc2. See module main.py for details import main main.main() Modified: trunk/jython/Tools/jythonc/main.py =================================================================== --- trunk/jython/Tools/jythonc/main.py 2007-09-13 00:21:35 UTC (rev 3471) +++ trunk/jython/Tools/jythonc/main.py 2007-09-13 01:11:26 UTC (rev 3472) @@ -1,6 +1,6 @@ # Copyright (c) Corporation for National Research Initiatives -"""Usage: jpythonc [options] [module]* +"""Usage: jythonc [options] [module]* where options include: @@ -22,11 +22,11 @@ --core -c - Include the core JPython libraries (implies --deep) + Include the core Jython libraries (implies --deep) --all -a - Include all of the JPython libraries (implies --deep) + Include all of the Jython libraries (implies --deep) --bean jarfile -b jarfile @@ -49,12 +49,12 @@ -C path Use a different compiler than `standard' javac. If this is set to `NONE' then compile ends with .java. Alternatively, you can set the - property python.jpythonc.compiler in the registry. + property python.jythonc.compiler in the registry. --compileropts options -J options Options passed directly to the Java compiler. Alternatively, you can - set the property python.jpythonc.compileropts in the registry. + set the property python.jythonc.compileropts in the registry. --falsenames names -f names Modified: trunk/jython/Tools/mkjava.py =================================================================== --- trunk/jython/Tools/mkjava.py 2007-09-13 00:21:35 UTC (rev 3471) +++ trunk/jython/Tools/mkjava.py 2007-09-13 01:11:26 UTC (rev 3472) @@ -22,7 +22,7 @@ if __name__ == '__main__': if len(sys.argv) != 4: - print 'usage: jpython mkjava.py java_name python_name directory' + print 'usage: jython mkjava.py java_name python_name directory' sys.exit(-1) directory = sys.argv[-1] Modified: trunk/jython/src/org/python/core/Options.java =================================================================== --- trunk/jython/src/org/python/core/Options.java 2007-09-13 00:21:35 UTC (rev 3471) +++ trunk/jython/src/org/python/core/Options.java 2007-09-13 01:11:26 UTC (rev 3472) @@ -8,7 +8,7 @@ */ public class Options { // Jython options. Some of these can be set from the command line - // options, but all can be controlled through the JPython registry + // options, but all can be controlled through the Jython registry /** * when an exception occurs in Java code, and it is not caught, should the @@ -32,7 +32,7 @@ public static boolean pollStandardIn = false; /** - * If true, JPython respects Java the accessibility flag for fields, + * If true, Jython respects Java the accessibility flag for fields, * methods, and constructors. This means you can only access public members. * Set this to false to access all members by toggling the accessible flag * on the member. Modified: trunk/jython/src/org/python/core/PyFile.java =================================================================== --- trunk/jython/src/org/python/core/PyFile.java 2007-09-13 00:21:35 UTC (rev 3471) +++ trunk/jython/src/org/python/core/PyFile.java 2007-09-13 01:11:26 UTC (rev 3472) @@ -1532,7 +1532,7 @@ // TBD: should this be removed? I think it's better to raise an // AttributeError than an IOError here. public PyObject fileno() { - throw Py.IOError("fileno() is not supported in jpython"); + throw Py.IOError("fileno() is not supported in jython"); } final String file_toString() { Modified: trunk/jython/src/org/python/core/PyFunction.java =================================================================== --- trunk/jython/src/org/python/core/PyFunction.java 2007-09-13 00:21:35 UTC (rev 3471) +++ trunk/jython/src/org/python/core/PyFunction.java 2007-09-13 01:11:26 UTC (rev 3472) @@ -78,7 +78,7 @@ public void __setattr__(String name, PyObject value) { // TBD: in CPython, func_defaults, func_doc, __doc__ are // writable. For now, only func_doc, __doc__ are writable in - // JPython. + // Jython. if (name == "func_doc" || name == "__doc__") __doc__ = value; else if (name == "func_closure") { Modified: trunk/jython/src/org/python/core/PySystemState.java =================================================================== --- trunk/jython/src/org/python/core/PySystemState.java 2007-09-13 00:21:35 UTC (rev 3471) +++ trunk/jython/src/org/python/core/PySystemState.java 2007-09-13 01:11:26 UTC (rev 3472) @@ -466,7 +466,7 @@ standalone = isStandalone(jarFileName); } - // initialize the JPython registry + // initialize the Jython registry initRegistry(preProperties, postProperties, standalone, jarFileName); // other initializations Modified: trunk/jython/src/org/python/core/PyTableCode.java =================================================================== --- trunk/jython/src/org/python/core/PyTableCode.java 2007-09-13 00:21:35 UTC (rev 3471) +++ trunk/jython/src/org/python/core/PyTableCode.java 2007-09-13 01:11:26 UTC (rev 3472) @@ -169,7 +169,7 @@ // Handle trace function for debugging PySystemState ss = ts.systemState; if (ss.tracefunc != null) { - // JPython and CPython differ here. CPython actually lays down + // Jython and CPython differ here. CPython actually lays down // an extra SET_LINENO bytecode for function definition line. // This is ostensibly so that a tuple unpacking failure in // argument passing gets the right line number in the @@ -177,7 +177,7 @@ // you'll see two 'line' events, one for the def line and then // immediately after, one for the first line of the function. // - // JPython on the other hand only lays down a call in the + // Jython on the other hand only lays down a call in the // generated Java function to set the line number for the first // line of the function (i.e. not the def line). This // difference in behavior doesn't seem to affect arg tuple Modified: trunk/jython/src/org/python/modules/MD5Module.java =================================================================== --- trunk/jython/src/org/python/modules/MD5Module.java 2007-09-13 00:21:35 UTC (rev 3471) +++ trunk/jython/src/org/python/modules/MD5Module.java 2007-09-13 01:11:26 UTC (rev 3472) @@ -1,6 +1,6 @@ // Copyright (c) Corporation for National Research Initiatives -// This is a JPython module wrapper around Harry Mantakos' md.java class, +// This is a Jython module wrapper around Harry Mantakos' md.java class, // which provides the basic MD5 algorithm. See also MD5Object.java which // is the implementation of the md5 object returned by new() and md.java // which provides the md5 implementation. Modified: trunk/jython/src/org/python/modules/Setup.java =================================================================== --- trunk/jython/src/org/python/modules/Setup.java 2007-09-13 00:21:35 UTC (rev 3471) +++ trunk/jython/src/org/python/modules/Setup.java 2007-09-13 01:11:26 UTC (rev 3472) @@ -21,7 +21,7 @@ // The module `name' is removed from the list of builtin modules // // That isn't very useful here, but you can add additional builtin - // modules by editing the JPython registry file. See the property + // modules by editing the Jython registry file. See the property // python.modules.builtin for details. public static String[] builtinModules = { Modified: trunk/jython/src/org/python/modules/imp.java =================================================================== --- trunk/jython/src/org/python/modules/imp.java 2007-09-13 00:21:35 UTC (rev 3471) +++ trunk/jython/src/org/python/modules/imp.java 2007-09-13 01:11:26 UTC (rev 3472) @@ -19,7 +19,7 @@ * A bogus implementation of the CPython builtin module "imp". * Only the functions required by IDLE and PMW are implemented. * Luckily these function are also the only function that IMO can - * be implemented under JPython. + * be implemented under Jython. */ public class imp { Modified: trunk/jython/src/org/python/modules/time/Time.java =================================================================== --- trunk/jython/src/org/python/modules/time/Time.java 2007-09-13 00:21:35 UTC (rev 3471) +++ trunk/jython/src/org/python/modules/time/Time.java 2007-09-13 01:11:26 UTC (rev 3472) @@ -554,7 +554,7 @@ // properties and is "en_US" by default, at least around // here! Locale "en_US" differs from locale "C" in the way // it represents dates and times. Eventually we might want - // to craft a "C" locale for Java and set JPython to use + // to craft a "C" locale for Java and set Jython to use // this by default, but that's too much work right now. // // For now, we hard code %x and %X to return values Modified: trunk/jython/src/org/python/util/InteractiveInterpreter.java =================================================================== --- trunk/jython/src/org/python/util/InteractiveInterpreter.java 2007-09-13 00:21:35 UTC (rev 3471) +++ trunk/jython/src/org/python/util/InteractiveInterpreter.java 2007-09-13 01:11:26 UTC (rev 3472) @@ -113,7 +113,7 @@ } /** Pause the current code, sneak an exception raiser into - * sys.trace_func, and then continue the code hoping that JPython will + * sys.trace_func, and then continue the code hoping that Jython will * get control to do the break; **/ public void interrupt(ThreadState ts) { Modified: trunk/jython/src/org/python/util/PyServlet.java =================================================================== --- trunk/jython/src/org/python/util/PyServlet.java 2007-09-13 00:21:35 UTC (rev 3471) +++ trunk/jython/src/org/python/util/PyServlet.java 2007-09-13 01:11:26 UTC (rev 3472) @@ -9,8 +9,8 @@ /** - * This servlet is used to re-serve JPython servlets. It stores - * bytecode for JPython servlets and re-uses it if the underlying .py + * This servlet is used to re-serve Jython servlets. It stores + * bytecode for Jython servlets and re-uses it if the underlying .py * file has not changed. * <p> * Many people have been involved with this class: Modified: trunk/jython/src/org/python/util/PythonInterpreter.java =================================================================== --- trunk/jython/src/org/python/util/PythonInterpreter.java 2007-09-13 00:21:35 UTC (rev 3471) +++ trunk/jython/src/org/python/util/PythonInterpreter.java 2007-09-13 01:11:26 UTC (rev 3472) @@ -4,7 +4,7 @@ import java.util.*; /** - * The PythonInterpreter class is a standard wrapper for a JPython + * The PythonInterpreter class is a standard wrapper for a Jython * interpreter for use embedding in a Java application. * * @author Jim Hugunin This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <cg...@us...> - 2007-09-15 23:31:14
|
Revision: 3477 http://jython.svn.sourceforge.net/jython/?rev=3477&view=rev Author: cgroves Date: 2007-09-15 16:31:12 -0700 (Sat, 15 Sep 2007) Log Message: ----------- Strip the default target, developer-build, down to the minimum needed to build jython.jar and get the Lib files in place Move the printing of all of Jython's build properties to a new target, dump-env, and only do that in full-build by default. This is essentially the patch I sent to jython-dev a couple months ago with Oti's suggestions. Modified Paths: -------------- trunk/jython/build.xml Added Paths: ----------- trunk/jython/CPythonLib.includes Removed Paths: ------------- trunk/jython/build.Lib.include.properties Copied: trunk/jython/CPythonLib.includes (from rev 3476, trunk/jython/build.Lib.include.properties) =================================================================== --- trunk/jython/CPythonLib.includes (rev 0) +++ trunk/jython/CPythonLib.includes 2007-09-15 23:31:12 UTC (rev 3477) @@ -0,0 +1,131 @@ +# files to be copied from the CPython Lib distribution, +# used as fileset in build.xml (target copy-full) + +# Lib directories, in alphabetical order: +email/** +encodings/** +logging/* +test/** + +# Lib files, in alphabetical order: +__future__.py +aifc.py +anydbm.py +atexit.py +BaseHTTPServer.py +base64.py +bdb.py +binhex.py +bisect.py +calendar.py +cgi.py +CGIHTTPServer.py +chunk.py +cmd.py +cmp.py +cmpcache.py +code.py +codecs.py +colorsys.py +commands.py +compileall.py +ConfigParser.py +copy.py +copy_reg.py +Cookie.py +difflib.py +dircache.py +dircmp.py +dospath.py +dumbdbm.py +exceptions.py +fileinput.py +fnmatch.py +formatter.py +fpformat.py +ftplib.py +getopt.py +glob.py +gopherlib.py +gzip.py +hmac.py +htmlentitydefs.py +htmllib.py +HTMLParser.py +httplib.py +imaplib.py +imghdr.py +inspect.py +keyword.py +linecache.py +macpath.py +macurl2path.py +mailbox.py +mailcap.py +markupbase.py +mhlib.py +mimetools.py +mimetypes.py +MimeWriter.py +mimify.py +multifile.py +mutex.py +netrc.py +nntplib.py +ntpath.py +nturl2path.py +pdb.py +pickle.py +pickletools.py +pipes.py +poplib.py +posixfile.py +posixpath.py +pprint.py +profile.py +pstats.py +pyclbr.py +Queue.py +quopri.py +random.py +reconvert.py +repr.py +rfc822.py +rlcompleter.py +sched.py +sgmllib.py +shelve.py +shlex.py +shutil.py +SimpleHTTPServer.py +SimpleXMLRPCServer.py +smtplib.py +sndhdr.py +SocketServer.py +sre*.py +stat.py +StringIO.py +symbol.py +this.py +threading.py +textwrap.py +token.py +tokenize.py +traceback.py +tzparse.py +unittest.py +urllib.py +urllib2.py +urlparse.py +user.py +UserDict.py +UserString.py +uu.py +warnings.py +weakref.py +whichdb.py +whrandom.py +xdrlib.py +xmllib.py +xmlrpclib.py +zipfile.py Deleted: trunk/jython/build.Lib.include.properties =================================================================== --- trunk/jython/build.Lib.include.properties 2007-09-15 23:25:10 UTC (rev 3476) +++ trunk/jython/build.Lib.include.properties 2007-09-15 23:31:12 UTC (rev 3477) @@ -1,131 +0,0 @@ -# files to be copied from the CPython Lib distribution, -# used as fileset in build.xml (target copy-full) - -# Lib directories, in alphabetical order: -email/** -encodings/** -logging/* -test/** - -# Lib files, in alphabetical order: -__future__.py -aifc.py -anydbm.py -atexit.py -BaseHTTPServer.py -base64.py -bdb.py -binhex.py -bisect.py -calendar.py -cgi.py -CGIHTTPServer.py -chunk.py -cmd.py -cmp.py -cmpcache.py -code.py -codecs.py -colorsys.py -commands.py -compileall.py -ConfigParser.py -copy.py -copy_reg.py -Cookie.py -difflib.py -dircache.py -dircmp.py -dospath.py -dumbdbm.py -exceptions.py -fileinput.py -fnmatch.py -formatter.py -fpformat.py -ftplib.py -getopt.py -glob.py -gopherlib.py -gzip.py -hmac.py -htmlentitydefs.py -htmllib.py -HTMLParser.py -httplib.py -imaplib.py -imghdr.py -inspect.py -keyword.py -linecache.py -macpath.py -macurl2path.py -mailbox.py -mailcap.py -markupbase.py -mhlib.py -mimetools.py -mimetypes.py -MimeWriter.py -mimify.py -multifile.py -mutex.py -netrc.py -nntplib.py -ntpath.py -nturl2path.py -pdb.py -pickle.py -pickletools.py -pipes.py -poplib.py -posixfile.py -posixpath.py -pprint.py -profile.py -pstats.py -pyclbr.py -Queue.py -quopri.py -random.py -reconvert.py -repr.py -rfc822.py -rlcompleter.py -sched.py -sgmllib.py -shelve.py -shlex.py -shutil.py -SimpleHTTPServer.py -SimpleXMLRPCServer.py -smtplib.py -sndhdr.py -SocketServer.py -sre*.py -stat.py -StringIO.py -symbol.py -this.py -threading.py -textwrap.py -token.py -tokenize.py -traceback.py -tzparse.py -unittest.py -urllib.py -urllib2.py -urlparse.py -user.py -UserDict.py -UserString.py -uu.py -warnings.py -weakref.py -whichdb.py -whrandom.py -xdrlib.py -xmllib.py -xmlrpclib.py -zipfile.py Modified: trunk/jython/build.xml =================================================================== --- trunk/jython/build.xml 2007-09-15 23:25:10 UTC (rev 3476) +++ trunk/jython/build.xml 2007-09-15 23:31:12 UTC (rev 3477) @@ -138,38 +138,19 @@ </echo> </target> + <target name="developer-build" depends="jar, copy-lib" description="a local build for developers" /> - <!-- developer build --> - <target name="developer-build" - depends="developer-build-called, developer-init, post-init, template, copy-dist" - description="a local build for developers" - /> + <target name="full-build" depends="full-init, dump-env, install" description="a full build from svn" /> - - <!-- full build --> - <target name="full-build" depends="full-init, post-init, install" description="a full build from svn" /> - - - <!-- set a property to indicate that target 'developer-build' was really called --> - <target name="developer-build-called"> - <property name="developer-build-called" value="true" /> - </target> - - - <!-- initialize properties common to both developer build and full build --> - <target name="pre-init"> - <!-- load from .properties file --> - <echo>loading properties from ${user.home}/ant.properties</echo> + <target name="common-init"> <property file="${user.home}/ant.properties" /> - <echo>loading properties from ${basedir}/ant.properties</echo> <property file="${basedir}/ant.properties" /> <property name="build.compiler" value="modern" /> <property name="jdk.target.version" value="1.5" /> <property name="jdk.source.version" value="1.5" /> <property name="deprecation" value="off" /> - <property name="debug" value="off" /> - <property name="optimize" value="on" /> + <property name="debug" value="true" /> <property name="nowarn" value="false" /> <!-- classpaths --> @@ -198,11 +179,6 @@ <available property="jndi.present" classname="javax.naming.Context" classpath="${jndi.jar}" /> <available property="javax.sql.present" classname="javax.sql.DataSource" /> <available property="jdbc30.present" classname="java.sql.ParameterMetaData" /> - </target> - - - <!-- init properties for the developer build --> - <target name="developer-init" depends="pre-init"> <property name="work.dir" value="${basedir}" /> <property name="jython.base.dir" value="${basedir}" /> <property name="source.dir" value="${basedir}/src" /> @@ -212,12 +188,9 @@ <property name="templates.lazy" value="true" /> </target> - - <!-- init properties for the full build --> - <target name="full-init" depends="pre-init"> + <target name="full-init" depends="common-init"> <!-- use this property to distinguish a full-build from a developer-build --> <property name="full-build" value="true" /> - <property name="do.templates" value="true" /> <!-- predefined tags for jython and cpython --> <property name="svn.tag" value="Release_2_2beta2" /> @@ -260,12 +233,14 @@ <fail unless="oracle.present" message="oracle jar not present" /> </target> - - <target name="post-init"> + <target name="init" depends="common-init"> <property name="output.dir" value="${work.dir}/build" /> <property name="dist.dir" value="${work.dir}/dist" /> <property name="apidoc.dir" value="${dist.dir}/Doc/javadoc" /> <property name="parser.dir" value="${source.dir}/org/python/parser" /> + </target> + + <target name="dump-env" depends="init"> <echo>.</echo> <echo>Build environment for ${ant.project.name}</echo> <echo>(Note: if ${propertyname} is displayed, then the property is not set)</echo> @@ -298,29 +273,22 @@ <echo>jdk.source.version = '${jdk.source.version}'</echo> <echo>deprecation = '${deprecation}'</echo> <echo>debug = '${debug}'</echo> - <echo>optimize = '${optimize}'</echo> <echo>nowarn = '${nowarn}'</echo> <echo>--- properties (used for full-build only ) ---</echo> <echo>python.exe = '${python.exe}'</echo> <echo>svn.tag = '${svn.tag}'</echo> <echo>svn.checkout.dir = '${svn.checkout.dir}'</echo> - <echo>javahl.dir = '${javahl.dir}'</echo> - <echo>svnant.jar.dir = '${svnant.jar.dir}'</echo> - <echo>svn.revision = '${svn.revision}'</echo> + <echo>javahl.dir = '${javahl.dir}'</echo> + <echo>svnant.jar.dir = '${svnant.jar.dir}'</echo> + <echo>svn.revision = '${svn.revision}'</echo> <echo>do.snapshot.build = '${do.snapshot.build}'</echo> <echo>do.checkout = '${do.checkout}'</echo> - <echo>do.templates = '${do.templates}'</echo> </target> - <!-- delete what's necessary. should correspond to the directories created in prepare --> <!-- if called directly, we use settings as in developer-build --> <!-- (at the moment all properties will already be set if we do a full build) --> - <target name="clean" - depends="developer-init, post-init, clean-checkout-dir" - unless="developer-build-called" - description="clean up build working directories" - > + <target name="clean" depends="init, clean-checkout-dir" description="clean up build working directories"> <!-- do not hard delete ${work.dir}, since it could be ${basedir} --> <!-- deletes all files and subdirectories of ${output.dir}, without ${output.dir} itself. --> <delete includeemptydirs="true" failonerror="false"> @@ -336,7 +304,6 @@ </delete> </target> - <!-- clean svn.checkout.dir if we really checkout --> <target name="clean-checkout-dir" if="do.checkout"> <delete includeemptydirs="true" failonerror="false"> @@ -344,14 +311,12 @@ </delete> </target> - <!-- create necessary directories --> <target name="prepare" depends="prepare-full, prepare-checkout"> <mkdir dir="${output.dir}" /> <mkdir dir="${dist.dir}" /> </target> - <!-- create directories needed only in full-build --> <target name="prepare-full" depends="clean" if="full-build"> <mkdir dir="${work.dir}" /> @@ -359,14 +324,11 @@ <mkdir dir="${apidoc.dir}" /> </target> - <!-- create checkout directory if necessary --> <target name="prepare-checkout" if="do.checkout"> <mkdir dir="${svn.checkout.dir}" /> </target> - - <!-- checkout if so defined --> <target name="checkout" depends="prepare" if="do.checkout"> <!-- determine if to checkout from /tags/${svn.tag} (any tag), or /trunk (HEAD) --> <condition property="svn.main.dir" value="trunk"> @@ -412,15 +374,12 @@ <!-- separate build.xml for parser grammar --> <!-- we use settings as in developer-build - at the moment all properties will already be set if we do a full build --> - <target name="parser" depends="developer-init, post-init, prepare" if="javaccHome" description="the grammar build"> + <target name="parser" depends="init, prepare" if="javaccHome" description="the grammar build"> <echo>processing ${parser.dir}/build.xml</echo> <ant dir="${parser.dir}" /> </target> - - <!-- prepare template ant task --> - <target name="template-init" depends="prepare" if="do.templates"> - + <target name="template-init" depends="prepare"> <javac srcdir="${source.dir}/" destdir="${output.dir}/" target="${jdk.target.version}" @@ -428,32 +387,26 @@ debug="${debug}" optimize="${optimize}" deprecation="${deprecation}" - nowarn="${nowarn}" - > + nowarn="${nowarn}"> <include name="org/python/util/TemplateAntTask.java" /> </javac> </target> - - <!-- run templates --> - <target name="template" depends="checkout, template-init" if="do.templates"> + <target name="template" depends="checkout, template-init"> <taskdef name="gentempl" classname="org.python.util.TemplateAntTask" classpath="${output.dir}" /> <gentempl srcdir="${templates.dir}" verbose="true" lazy="${templates.lazy}"/> </target> - - <!-- compile java sources --> - <target name="compile" depends="version, parser"> + <target name="compile" depends="init"> <javac srcdir="${source.dir}/" destdir="${output.dir}/" target="${jdk.target.version}" source="${jdk.source.version}" debug="${debug}" - optimize="${optimize}" deprecation="${deprecation}" - nowarn="${nowarn}" + nowarn="${nowarn}" > <exclude name="org/python/parser/python.java" /> <exclude name="**/PyServlet.java" unless="servlet.present" /> @@ -505,8 +458,6 @@ </copy> </target> - - <!-- build jython.jar --> <target name="jar" depends="compile"> <jar destfile="${dist.dir}/jython.jar" basedir="${output.dir}" @@ -543,7 +494,6 @@ </jar> </target> - <!-- build the .html files using the ht2html tool --> <target name="doc" depends="compile" if="full-build"> <fail unless="ht2html.dir" message="ht2html.dir is not set" /> @@ -564,9 +514,7 @@ </delete> </target> - - <!-- javadoc --> - <target name="javadoc" depends="compile" if="full-build"> + <target name="javadoc" depends="compile"> <javadoc sourcepath="${source.dir}" destdir="${apidoc.dir}" source="${jdk.source.version}" @@ -580,10 +528,7 @@ </javadoc> </target> - - <!-- copy for full distribution --> - <target name="copy-full" if="full-build"> - <!-- Misc files --> + <target name="copy-full" depends="copy-lib" if="full-build"> <echo>copy misc files from ${jython.base.dir}</echo> <copy todir="${dist.dir}" preservelastmodified="true"> <fileset dir="${jython.base.dir}" @@ -591,7 +536,6 @@ /> </copy> - <!-- copy the CPython license --> <echo>copy CPython LICENSE from ${svn.checkout.dir}/python</echo> <copy file="${svn.checkout.dir}/python/LICENSE" tofile="${dist.dir}/LICENSE_CPython.txt" preservelastmodified="true" /> @@ -609,7 +553,6 @@ </fileset> </copy> - <!-- The demo files --> <echo>copy the demo files from ${jython.base.dir}/Demo</echo> <copy todir="${dist.dir}/Demo" preservelastmodified="true"> <fileset dir="${jython.base.dir}/Demo"> @@ -625,37 +568,22 @@ </copy> </target> - - <!-- copy for distribution --> - <target name="copy-dist" depends="jar, doc, javadoc, copy-full"> - <!-- Tools: jythonc and freeze --> - <echo>copy Tools from ${jython.base.dir}/Tools</echo> + <target name="copy-lib" depends="init"> <copy todir="${dist.dir}" preservelastmodified="true"> <fileset dir="${jython.base.dir}" includes="Tools/**/*.py" /> </copy> - <!-- Copy the CPython standard library files --> - <echo>copy CPython/Lib *.py files from ${python.lib}</echo> - <copy todir="${dist.dir}/Lib" preservelastmodified="true"> - <fileset dir="${python.lib}" excludes="**/*.pyc, **/*.pyo"> - <patternset> - <includesfile name="${jython.base.dir}/build.Lib.include.properties" /> - <exclude name="test/output/test_sax"/> - <exclude name="test/output/test_zlib"/> - </patternset> + <copy todir="${dist.dir}/Lib"> + <fileset dir="${jython.base.dir}/Lib" excludes="**/*.class"/> + <fileset dir="${python.lib}" excludes="**/*.pyc, **/*.pyo" includesfile="${jython.base.dir}/CPythonLib.includes"> + <!-- The include file gets all of CPythonLib's test directory, but we only want the ones from Jython's Lib. --> + <present present="srconly" targetdir="${jython.base.dir}/Lib"/> </fileset> </copy> - - <!-- The jython .py modules: important to overwrite the above CPython .py files --> - <echo>copy the jython *.py modules from ${jython.base.dir}/Lib</echo> - <copy todir="${dist.dir}/Lib" preservelastmodified="true" overwrite="true"> - <fileset dir="${jython.base.dir}/Lib" excludes="**/*.class"/> - </copy> </target> - <!-- wrap the build into the installer --> - <target name="install" depends="copy-dist"> + <target name="install" depends="version, doc, javadoc, jar, copy-full"> <fail unless="svn.tag" message="no svn.tag specified" /> <property name="install.src.dir" value="${jython.base.dir}/../installer/src/java" /> <echo>compiling installer from ${install.src.dir}</echo> @@ -716,8 +644,7 @@ </jar> </target> - <!-- run regression test suite --> - <target name="regrtest" depends="developer-init, post-init"> + <target name="regrtest" depends="init"> <java classname="org.python.util.jython" fork="true"> <jvmarg value="-Dpython.home=${dist.dir}"/> <arg value="${dist.dir}/Lib/test/regrtest.py"/> @@ -728,7 +655,7 @@ </target> <!-- run bugtests, create a config if necessary --> - <target name="bugtest" depends="developer-init, post-init, create-bugtest-config"> + <target name="bugtest" depends="create-bugtest-config"> <java classname="org.python.util.jython" fork="true" dir="${bugtests.dir}"> <classpath> <pathelement location="${dist.dir}/jython.jar"/> @@ -743,7 +670,7 @@ </target> <!-- create support_config.py in the bugtset directory only if it doesn't already exist --> - <target name="create-bugtest-config" depends="developer-init, post-init, check-bugtest-config" unless="have_bugtest_config"> + <target name="create-bugtest-config" depends="init, check-bugtest-config" unless="have_bugtest_config"> <!-- doesn't seem to be a direct way to get at the path to javac, java.home points to the jre folder. The following assumes a standard jdk layout. Alternative is to try something like: This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <cg...@us...> - 2007-09-19 08:59:34
|
Revision: 3480 http://jython.svn.sourceforge.net/jython/?rev=3480&view=rev Author: cgroves Date: 2007-09-19 01:59:31 -0700 (Wed, 19 Sep 2007) Log Message: ----------- Replace all String to byte and byte to String operations that use the default charset with PyString.to_bytes and PyString.from_bytes respectively. These methods assume Strings are being used as byte arrays and have nothing in the high-order half of their chars. They should be used be your one stop shop for byte to String and vice-versa manipulations in Jython. Also make PyUnicode.__str__ encode its string before stuffing it in a PyString. Hopefully this fixes our stomp-indiscriminately-on-your-bytes features that come up if your JVM has a flavorful default charset. Modified Paths: -------------- trunk/jython/Lib/test/test_builtin.py trunk/jython/src/com/ziclix/python/sql/DataHandler.java trunk/jython/src/com/ziclix/python/sql/JDBC20DataHandler.java trunk/jython/src/com/ziclix/python/sql/handler/MySQLDataHandler.java trunk/jython/src/org/python/core/FilelikeInputStream.java trunk/jython/src/org/python/core/Py.java trunk/jython/src/org/python/core/PyArray.java trunk/jython/src/org/python/core/PyFile.java trunk/jython/src/org/python/core/PyString.java trunk/jython/src/org/python/core/PyUnicode.java trunk/jython/src/org/python/core/StdoutWrapper.java trunk/jython/src/org/python/core/parser.java trunk/jython/src/org/python/modules/SHA1.java trunk/jython/src/org/python/modules/binascii.java trunk/jython/src/org/python/modules/zipimport/zipimporter.java Modified: trunk/jython/Lib/test/test_builtin.py =================================================================== --- trunk/jython/Lib/test/test_builtin.py 2007-09-17 22:47:48 UTC (rev 3479) +++ trunk/jython/Lib/test/test_builtin.py 2007-09-19 08:59:31 UTC (rev 3480) @@ -264,8 +264,8 @@ # unicode bom isn't recognized to indicate unicode for parsing # http://jython.org/1768968 # self.assertEqual(eval(bom + 'a', globals, locals), 1) - self.assertEqual(eval(unicode('u"\xc3\xa5"', 'utf8'), globals), - unicode('\xc3\xa5', 'utf8')) +# self.assertEqual(eval(unicode('u"\xc3\xa5"', 'utf8'), globals), +# unicode('\xc3\xa5', 'utf8')) self.assertRaises(TypeError, eval) self.assertRaises(TypeError, eval, ()) Modified: trunk/jython/src/com/ziclix/python/sql/DataHandler.java =================================================================== --- trunk/jython/src/com/ziclix/python/sql/DataHandler.java 2007-09-17 22:47:48 UTC (rev 3479) +++ trunk/jython/src/com/ziclix/python/sql/DataHandler.java 2007-09-19 08:59:31 UTC (rev 3480) @@ -250,7 +250,7 @@ byte[] bytes = DataHandler.read(longvarchar); if (bytes != null) { - obj = Py.newString(new String(bytes)); + obj = Py.newString(PyString.from_bytes(bytes)); } } finally { try { Modified: trunk/jython/src/com/ziclix/python/sql/JDBC20DataHandler.java =================================================================== --- trunk/jython/src/com/ziclix/python/sql/JDBC20DataHandler.java 2007-09-17 22:47:48 UTC (rev 3479) +++ trunk/jython/src/com/ziclix/python/sql/JDBC20DataHandler.java 2007-09-19 08:59:31 UTC (rev 3480) @@ -66,7 +66,7 @@ String clob = (String) object.__tojava__(String.class); int length = clob.length(); - InputStream stream = new ByteArrayInputStream(clob.getBytes()); + InputStream stream = new ByteArrayInputStream(PyString.to_bytes(clob)); stream = new BufferedInputStream(stream); Modified: trunk/jython/src/com/ziclix/python/sql/handler/MySQLDataHandler.java =================================================================== --- trunk/jython/src/com/ziclix/python/sql/handler/MySQLDataHandler.java 2007-09-17 22:47:48 UTC (rev 3479) +++ trunk/jython/src/com/ziclix/python/sql/handler/MySQLDataHandler.java 2007-09-19 08:59:31 UTC (rev 3480) @@ -11,6 +11,7 @@ import com.ziclix.python.sql.DataHandler; import org.python.core.PyFile; import org.python.core.PyObject; +import org.python.core.PyString; import java.io.BufferedInputStream; import java.io.ByteArrayInputStream; @@ -59,7 +60,7 @@ } else { varchar = (String) object.__tojava__(String.class); } - InputStream stream = new ByteArrayInputStream(varchar.getBytes()); + InputStream stream = new ByteArrayInputStream(PyString.to_bytes(varchar)); stream = new BufferedInputStream(stream); Modified: trunk/jython/src/org/python/core/FilelikeInputStream.java =================================================================== --- trunk/jython/src/org/python/core/FilelikeInputStream.java 2007-09-17 22:47:48 UTC (rev 3479) +++ trunk/jython/src/org/python/core/FilelikeInputStream.java 2007-09-19 08:59:31 UTC (rev 3480) @@ -34,7 +34,7 @@ if(result.length() == 0) { return -1; } - System.arraycopy(result.getBytes(), 0, b, off, result.length()); + System.arraycopy(PyString.to_bytes(result), 0, b, off, result.length()); return result.length(); } Modified: trunk/jython/src/org/python/core/Py.java =================================================================== --- trunk/jython/src/org/python/core/Py.java 2007-09-17 22:47:48 UTC (rev 3479) +++ trunk/jython/src/org/python/core/Py.java 2007-09-19 08:59:31 UTC (rev 3480) @@ -1,6 +1,7 @@ // Copyright (c) Corporation for National Research Initiatives package org.python.core; +import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileOutputStream; @@ -1764,12 +1765,14 @@ cflags); } - public static PyCode compile_flags(String data, String filename, - String type,CompilerFlags cflags) - { - return Py.compile_flags( - new java.io.ByteArrayInputStream((data+"\n\n").getBytes()), - filename, type,cflags); + public static PyCode compile_flags(String data, + String filename, + String type, + CompilerFlags cflags) { + return Py.compile_flags(new ByteArrayInputStream(PyString.to_bytes(data + "\n\n")), + filename, + type, + cflags); } public static PyObject compile_command_flags(String string, Modified: trunk/jython/src/org/python/core/PyArray.java =================================================================== --- trunk/jython/src/org/python/core/PyArray.java 2007-09-17 22:47:48 UTC (rev 3479) +++ trunk/jython/src/org/python/core/PyArray.java 2007-09-19 08:59:31 UTC (rev 3480) @@ -1270,7 +1270,7 @@ if((strlen % itemsize) != 0) { throw Py.ValueError("string length not a multiple of item size"); } - ByteArrayInputStream bis = new ByteArrayInputStream(input.getBytes()); + ByteArrayInputStream bis = new ByteArrayInputStream(PyString.to_bytes(input)); int origsize = delegate.getSize(); try { fromStream(bis); @@ -1674,7 +1674,7 @@ delegate.replaceSubArray(chars, start); } else { if(value instanceof PyString && type == Byte.TYPE) { - byte[] chars = value.toString().getBytes(); + byte[] chars = ((PyString)value).getBytes(); if(chars.length == stop - start && step == 1) { System.arraycopy(chars, 0, data, start, chars.length); } else { @@ -1724,8 +1724,7 @@ throw Py.TypeError("file needs to be in write or append mode"); } // write via the PyFile - String buffer = tostring(); - file.write(buffer); + file.write(tostring()); } public PyObject array_tolist(){ @@ -1804,12 +1803,6 @@ } catch(IOException e) { throw Py.IOError(e); } - try { - // The returned string is used as a Python str with values - // from 0-255. iso-8859-1 maps the byte values into that range. - return new String(bos.toByteArray(), "iso-8859-1"); - } catch (UnsupportedEncodingException e) { - throw Py.JavaError(e); - } + return PyString.from_bytes(bos.toByteArray()); } } Modified: trunk/jython/src/org/python/core/PyFile.java =================================================================== --- trunk/jython/src/org/python/core/PyFile.java 2007-09-17 22:47:48 UTC (rev 3479) +++ trunk/jython/src/org/python/core/PyFile.java 2007-09-19 08:59:31 UTC (rev 3480) @@ -4,13 +4,12 @@ import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; -import java.io.InputStream; import java.io.IOException; +import java.io.InputStream; import java.io.OutputStream; import java.io.PushbackInputStream; import java.io.RandomAccessFile; import java.io.Writer; - import java.util.LinkedList; // To do: @@ -69,24 +68,6 @@ public Object __tojava__(Class cls) throws IOException { return null; } - protected byte[] getBytes(String s) { - // Yes, I known the method is depricated, but it is the fastest - // way of converting between between byte[] and String - if (binary) { - byte[] buf = new byte[s.length()]; - s.getBytes(0, s.length(), buf, 0); - return buf; - } else - return s.getBytes(); - } - protected String getString(byte[] buf, int offset, int len) { - // Yes, I known the method is depricated, but it is the fastest - // way of converting between between byte[] and String - if (binary) { - return new String(buf, 0, offset, len); - } else - return new String(buf, offset, len); - } } private static class InputStreamWrapper extends FileWrapper { @@ -105,7 +86,7 @@ byte buf[] = new byte[1024]; StringBuffer sbuf = new StringBuffer(); for (int read=0; read >= 0; read=istream.read(buf)) - sbuf.append(getString(buf, 0, read)); + sbuf.append(PyString.from_bytes(buf, 0, read)); return sbuf.toString(); } // read the next chunk available, but make sure it's at least @@ -118,7 +99,7 @@ if (read < 0) // EOF encountered return ""; - return new String(buf, 0, 0, read); + return PyString.from_bytes(buf, 0, read); } public int read() throws IOException { @@ -154,7 +135,7 @@ private static final int MAX_WRITE = 30000; public void write(String s) throws IOException { - byte[] bytes = getBytes(s); + byte[] bytes = PyString.to_bytes(s); int n = bytes.length; int i = 0; while (i < n) { @@ -190,7 +171,7 @@ } public void write(String s) throws IOException { - ostream.write(getBytes(s)); + ostream.write(PyString.to_bytes(s)); } public void flush() throws IOException { @@ -289,7 +270,7 @@ n = readBytes(buf, 0, n); if (n < 0) n = 0; - return getString(buf, 0, n); + return PyString.from_bytes(buf, 0, n); } @@ -375,7 +356,7 @@ } public void write(String s) throws IOException { - byte[] b = getBytes(s); + byte[] b = PyString.to_bytes(s); int len = b.length; // If the amount of data is small (less than a full buffer)... @@ -1659,6 +1640,4 @@ } } } - - } Modified: trunk/jython/src/org/python/core/PyString.java =================================================================== --- trunk/jython/src/org/python/core/PyString.java 2007-09-17 22:47:48 UTC (rev 3479) +++ trunk/jython/src/org/python/core/PyString.java 2007-09-19 08:59:31 UTC (rev 3480) @@ -2099,21 +2099,41 @@ return cached_hashcode; } - private byte[] getBytes() { - return to_bytes(string); + /** + * @return a byte array with one byte for each char in this object's + * underlying String. Each byte contains the low-order bits of its + * corresponding char. + */ + public byte[] getBytes() { + return to_bytes(string); } + + /** + * @return a byte array with one byte for each char in s. Each byte contains + * the low-order bits of its corresponding char. + */ + public static byte[] to_bytes(String s) { + int len = s.length(); + byte[] b = new byte[len]; + s.getBytes(0, len, b, 0); + return b; + } + + /** + * @return A String with chars corresponding to the bytes in buf + */ + public static String from_bytes(byte[] buf) { + return from_bytes(buf, 0, buf.length); + } - public static byte[] to_bytes(String s){ - byte[] bytes = new byte[s.length()]; - for(int i = 0; i < bytes.length; i++) { - char c = s.charAt(i); - if(c < 256){ - bytes[i] = (byte)c; - }else{ - throw Py.ValueError("Strings added to sha hashes must not contain characters with value > 255"); - } - } - return bytes; + /** + * @return A String of len buff with chars corresponding to buf from off to + * off + len + */ + public static String from_bytes(byte[] buf, int off, int len) { + // Yes, I known the method is deprecated, but it is the fastest + // way of converting between between byte[] and String + return new String(buf, 0, off, len); } public Object __tojava__(Class c) { @@ -3139,7 +3159,7 @@ if (i > 0){ buf.append(string); } - buf.append(obj.__str__()); + buf.append(((PyString)obj).string); } if(needsUnicode || this instanceof PyUnicode){ return new PyUnicode(buf.toString()); Modified: trunk/jython/src/org/python/core/PyUnicode.java =================================================================== --- trunk/jython/src/org/python/core/PyUnicode.java 2007-09-17 22:47:48 UTC (rev 3479) +++ trunk/jython/src/org/python/core/PyUnicode.java 2007-09-19 08:59:31 UTC (rev 3480) @@ -1488,7 +1488,7 @@ return new PyUnicode(""); } if (S instanceof PyUnicode) { - return new PyUnicode( (String)S.__tojava__(String.class) ); + return new PyUnicode(((PyUnicode)S).string); } if (S instanceof PyString) { return new PyUnicode(codecs.decode((PyString)S, encoding, errors).toString()); @@ -1527,7 +1527,7 @@ } public PyString unicode___str__() { - return new PyString(toString()); + return new PyString(encode()); } final int unicode___len__() { Modified: trunk/jython/src/org/python/core/StdoutWrapper.java =================================================================== --- trunk/jython/src/org/python/core/StdoutWrapper.java 2007-09-17 22:47:48 UTC (rev 3479) +++ trunk/jython/src/org/python/core/StdoutWrapper.java 2007-09-19 08:59:31 UTC (rev 3480) @@ -71,7 +71,7 @@ } public void write(byte[] data, int off, int len) { - write(new String(data, off, len)); + write(PyString.from_bytes(data, off, len)); } public void clearSoftspace() { Modified: trunk/jython/src/org/python/core/parser.java =================================================================== --- trunk/jython/src/org/python/core/parser.java 2007-09-17 22:47:48 UTC (rev 3479) +++ trunk/jython/src/org/python/core/parser.java 2007-09-19 08:59:31 UTC (rev 3480) @@ -1,9 +1,23 @@ // Copyright (c) Corporation for National Research Initiatives package org.python.core; -import org.python.parser.*; +import java.io.BufferedReader; +import java.io.ByteArrayInputStream; +import java.io.FilterReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.Reader; +import java.io.UnsupportedEncodingException; + +import org.python.parser.IParserHost; +import org.python.parser.Node; +import org.python.parser.ParseException; +import org.python.parser.PythonGrammar; +import org.python.parser.ReaderCharStream; +import org.python.parser.Token; +import org.python.parser.TokenMgrError; import org.python.parser.ast.modType; -import java.io.*; /** * Facade for the classes in the org.python.parser package. @@ -75,7 +89,7 @@ public static Node parse(String string, String kind) { - return parse(new ByteArrayInputStream(string.getBytes()), + return parse(new ByteArrayInputStream(PyString.to_bytes(string)), kind, "<string>", null); } @@ -103,7 +117,7 @@ modType node = null; //System.err.println(new PyString(string).__repr__().toString()); - BufferedReader bufreader = prepBufreader(new ByteArrayInputStream(string.getBytes()), + BufferedReader bufreader = prepBufreader(new ByteArrayInputStream(PyString.to_bytes(string)), cflags); PythonGrammar g = new PythonGrammar(new ReaderCharStream(bufreader), Modified: trunk/jython/src/org/python/modules/SHA1.java =================================================================== --- trunk/jython/src/org/python/modules/SHA1.java 2007-09-17 22:47:48 UTC (rev 3479) +++ trunk/jython/src/org/python/modules/SHA1.java 2007-09-19 08:59:31 UTC (rev 3480) @@ -492,12 +492,7 @@ ); public String digest() { - byte[] digestBits = engineDigest(); - try { - return new String(digestBits, "ISO-8859-1"); - } catch (UnsupportedEncodingException exc) { - throw Py.ValueError("encoding not supported"); - } + return PyString.from_bytes(engineDigest()); } // XXX should become PyObject and use Py.idstr? Modified: trunk/jython/src/org/python/modules/binascii.java =================================================================== --- trunk/jython/src/org/python/modules/binascii.java 2007-09-17 22:47:48 UTC (rev 3479) +++ trunk/jython/src/org/python/modules/binascii.java 2007-09-19 08:59:31 UTC (rev 3480) @@ -203,8 +203,7 @@ }; private static byte[] table_b2a_hqx = - "!\"#$%&'()*+,-012345689@ABCDEFGHIJKLMNPQRSTUVXYZ[`abcdefhijklmpqr". - getBytes(); + PyString.to_bytes("!\"#$%&'()*+,-012345689@ABCDEFGHIJKLMNPQRSTUVXYZ[`abcdefhijklmpqr"); @@ -226,8 +225,7 @@ private static int BASE64_MAXBIN = 57; private static byte[] table_b2a_base64 = - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/". - getBytes(); + PyString.to_bytes("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"); Modified: trunk/jython/src/org/python/modules/zipimport/zipimporter.java =================================================================== --- trunk/jython/src/org/python/modules/zipimport/zipimporter.java 2007-09-17 22:47:48 UTC (rev 3479) +++ trunk/jython/src/org/python/modules/zipimport/zipimporter.java 2007-09-19 08:59:31 UTC (rev 3480) @@ -493,13 +493,7 @@ // continue } } - try { - return new String(data, "iso-8859-1"); - } - catch (UnsupportedEncodingException uee) { - // should never happen - throw new RuntimeException(uee); - } + return PyString.from_bytes(data); } public boolean is_package(String fullname) { This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <pj...@us...> - 2007-09-22 00:01:23
|
Revision: 3494 http://jython.svn.sourceforge.net/jython/?rev=3494&view=rev Author: pjenvey Date: 2007-09-21 17:01:20 -0700 (Fri, 21 Sep 2007) Log Message: ----------- o add universal newline support (PEP 278) o fix file text mode bugs: - text mode reading has historically acted like universal mode (with a couple bugs), it now acts like CPython's (adapting to the platform's newline) - text mode writing wasn't correctly identifying LF newline platforms - add test_file_newlines.py for testing text mode newline behavior o cleanup and pull file mode parsing out into its own sanitizeMode method o remove the test_uu workaround for lack of universal newline support and test_univnewlines from expected failures fixes #1755361 Modified Paths: -------------- trunk/jython/Lib/test/regrtest.py trunk/jython/src/org/python/core/PyFile.java trunk/jython/src/templates/file.expose Added Paths: ----------- trunk/jython/Lib/test/test_file_newlines.py Removed Paths: ------------- trunk/jython/Lib/test/test_uu.py Modified: trunk/jython/Lib/test/regrtest.py =================================================================== --- trunk/jython/Lib/test/regrtest.py 2007-09-21 20:13:18 UTC (rev 3493) +++ trunk/jython/Lib/test/regrtest.py 2007-09-22 00:01:20 UTC (rev 3494) @@ -1014,7 +1014,6 @@ test_timing test_unicode_file test_unicodedata - test_univnewlines test_urllibnet test_wave test_weakref Added: trunk/jython/Lib/test/test_file_newlines.py =================================================================== --- trunk/jython/Lib/test/test_file_newlines.py (rev 0) +++ trunk/jython/Lib/test/test_file_newlines.py 2007-09-22 00:01:20 UTC (rev 3494) @@ -0,0 +1,176 @@ +"""Test handling of newlines via file's read and readline + +Made for Jython. +""" +import os +import tempfile +import test.test_support as test_support +import unittest + +assert not os.linesep == '\r', ('os.linesep of %r is not supported' % + os.linesep) + +LF = os.linesep == '\n' +CRLF = os.linesep == '\r\n' + +CRLF_TEST = 'CR\rLF\nCRLF\r\nEOF' + +class BaseTestCase(unittest.TestCase): + + data = CRLF_TEST + write_mode = 'wb' + mode = 'r' + + def setUp(self): + self.filename = tempfile.mktemp() + fp = open(self.filename, self.write_mode) + fp.write(self.data) + fp.close() + self.fp = open(self.filename, self.mode) + + def tearDown(self): + if self.fp: + self.fp.close() + os.remove(self.filename) + + +class BinaryNewlinesTestCase(BaseTestCase): + + mode = 'rb' + + def test_binary_read(self): + read(self.fp, CRLF_TEST) + + self.fp.seek(0) + read(self.fp, CRLF_TEST, len(CRLF_TEST)) + + def test_binary_readline(self): + readline(self.fp, 'CR\rLF\n') + readline(self.fp, 'CRLF\r\n') + readline(self.fp, 'EOF') + + +class ReadTextNewlinesTestCase(BaseTestCase): + + def test_text_read(self): + if LF: + read(self.fp, 'CR\rLF\nCRLF\r\nEOF') + elif CRLF: + read(self.fp, 'CR\rLF\nCRLF\nEOF') + + self.fp.seek(0) + read(self.fp, 'CR\r', 3) + read(self.fp, 'LF\n', 3) + if LF: + read(self.fp, 'CRLF\r\n', 6) + elif CRLF: + read(self.fp, 'CRLF\n', 5) + read(self.fp, 'EOF', 3) + + def _test_text_readline(self): + readline(self.fp, 'CR\rLF\n') + if LF: + readline(self.fp, 'CRLF\r\n') + elif CRLF: + readline(self.fp, 'CRLF\n') + readline(self.fp, 'EOF') + + self.fp.seek(0) + readline(self.fp, 'CR\rLF\n') + if LF: + readline(self.fp, 'CRLF\r', 5) + readline(self.fp, '\n') + elif CRLF: + readline(self.fp, 'CRLF\n', 5) + readline(self.fp, 'EOF') + + +class ReadTextBoundaryTestCase(BaseTestCase): + + data = 'CR\r' + + def test_read_boundary(self): + read(self.fp, 'CR\r') + self.fp.seek(0) + read(self.fp, 'CR\r', 3) + + def test_readline_boundary(self): + readline(self.fp, 'CR\r') + self.fp.seek(0) + readline(self.fp, 'CR\r', 3) + + +class WriteTextNewlinesTestCase(BaseTestCase): + + write_mode = 'w' + mode = 'rb' + + def test_text_written(self): + if LF: + readline(self.fp, 'CR\rLF\n') + readline(self.fp, 'CRLF\r\n') + elif CRLF: + readline(self.fp, 'CR\rLF\r\n') + readline(self.fp, 'CRLF\r\r\n') + readline(self.fp, 'EOF') + + +class ReadUniversalNewlinesTestCase(BaseTestCase): + + mode = 'rU' + + def test_read(self): + read(self.fp, 'CR\nLF\nCRLF\nEOF') + + self.fp.seek(0) + read(self.fp, 'CR\nLF\nCRLF\nEOF', 14) + + def test_readline(self): + readline(self.fp, 'CR\n') + assert self.fp.newlines == None, repr(self.fp.newlines) + readline(self.fp, 'LF\n') + assert self.fp.newlines == ('\r', '\n'), repr(self.fp.newlines) + readline(self.fp, 'CRLF\n') + assert self.fp.newlines == ('\r', '\n'), repr(self.fp.newlines) + readline(self.fp, 'EOF') + assert self.fp.newlines == ('\r', '\n', '\r\n'), repr(self.fp.newlines) + + self.fp.seek(0) + readline(self.fp, 'CR\n', 3) + readline(self.fp, 'LF\n', 3) + readline(self.fp, 'CRLF\n', 5) + readline(self.fp, 'EOF', 3) + + +class WriteUniversalNewlinesTestCase(unittest.TestCase): + + def test_fails(self): + try: + open(tempfile.mktemp(), 'wU') + except ValueError: + pass + else: + raise AssertionError("file mode 'wU' did not raise a " + "ValueError") + + +def read(fp, data, size=-1): + line = fp.read(size) + assert line == data, 'read: %r expected: %r' % (line, data) + + +def readline(fp, data, size=-1): + line = fp.readline(size) + assert line == data, 'readline: %r expected: %r' % (line, data) + + +def test_main(): + test_support.run_unittest(BinaryNewlinesTestCase, + ReadTextNewlinesTestCase, + ReadTextBoundaryTestCase, + WriteTextNewlinesTestCase, + ReadUniversalNewlinesTestCase, + WriteUniversalNewlinesTestCase) + +if __name__ == '__main__': + test_main() Deleted: trunk/jython/Lib/test/test_uu.py =================================================================== --- trunk/jython/Lib/test/test_uu.py 2007-09-21 20:13:18 UTC (rev 3493) +++ trunk/jython/Lib/test/test_uu.py 2007-09-22 00:01:20 UTC (rev 3494) @@ -1,173 +0,0 @@ -""" -Tests for uu module. -Nick Mathewson -""" - -import unittest -from test import test_support - -import sys, os, uu, cStringIO -import uu -from StringIO import StringIO - -plaintext = "The smooth-scaled python crept over the sleeping dog\n" - -encodedtext = """\ -M5&AE('-M;V]T:\"US8V%L960@<'ET:&]N(&-R97!T(&]V97(@=&AE('-L965P -(:6YG(&1O9PH """ - -encodedtextwrapped = "begin %03o %s\n" + encodedtext.replace("%", "%%") + "\n \nend\n" - -class UUTest(unittest.TestCase): - - def test_encode(self): - inp = cStringIO.StringIO(plaintext) - out = cStringIO.StringIO() - uu.encode(inp, out, "t1") - self.assertEqual(out.getvalue(), encodedtextwrapped % (0666, "t1")) - inp = cStringIO.StringIO(plaintext) - out = cStringIO.StringIO() - uu.encode(inp, out, "t1", 0644) - self.assertEqual(out.getvalue(), encodedtextwrapped % (0644, "t1")) - - def test_decode(self): - inp = cStringIO.StringIO(encodedtextwrapped % (0666, "t1")) - out = cStringIO.StringIO() - uu.decode(inp, out) - self.assertEqual(out.getvalue(), plaintext) - inp = cStringIO.StringIO( - "UUencoded files may contain many lines,\n" + - "even some that have 'begin' in them.\n" + - encodedtextwrapped % (0666, "t1") - ) - out = cStringIO.StringIO() - uu.decode(inp, out) - self.assertEqual(out.getvalue(), plaintext) - - def test_truncatedinput(self): - inp = cStringIO.StringIO("begin 644 t1\n" + encodedtext) - out = cStringIO.StringIO() - try: - uu.decode(inp, out) - self.fail("No exception thrown") - except uu.Error, e: - self.assertEqual(str(e), "Truncated input file") - - def test_missingbegin(self): - inp = cStringIO.StringIO("") - out = cStringIO.StringIO() - try: - uu.decode(inp, out) - self.fail("No exception thrown") - except uu.Error, e: - self.assertEqual(str(e), "No valid begin line found in input file") - -class UUStdIOTest(unittest.TestCase): - - def setUp(self): - self.stdin = sys.stdin - self.stdout = sys.stdout - - def tearDown(self): - sys.stdin = self.stdin - sys.stdout = self.stdout - - def test_encode(self): - sys.stdin = cStringIO.StringIO(plaintext) - sys.stdout = cStringIO.StringIO() - uu.encode("-", "-", "t1", 0666) - self.assertEqual( - sys.stdout.getvalue(), - encodedtextwrapped % (0666, "t1") - ) - - def test_decode(self): - sys.stdin = cStringIO.StringIO(encodedtextwrapped % (0666, "t1")) - sys.stdout = cStringIO.StringIO() - uu.decode("-", "-") - self.assertEqual(sys.stdout.getvalue(), plaintext) - -class UUFileTest(unittest.TestCase): - - def _kill(self, f): - # close and remove file - try: - f.close() - except (SystemExit, KeyboardInterrupt): - raise - except: - pass - try: - os.unlink(f.name) - except (SystemExit, KeyboardInterrupt): - raise - except: - pass - - def setUp(self): - self.tmpin = test_support.TESTFN + "i" - self.tmpout = test_support.TESTFN + "o" - - def tearDown(self): - del self.tmpin - del self.tmpout - - def test_encode(self): - try: - fin = open(self.tmpin, 'wb') - fin.write(plaintext) - fin.close() - - fin = open(self.tmpin, 'rb') - fout = open(self.tmpout, 'w') - uu.encode(fin, fout, self.tmpin, mode=0644) - fin.close() - fout.close() - - fout = open(self.tmpout, 'r') - s = fout.read() - fout.close() - self.assertEqual(s, encodedtextwrapped % (0644, self.tmpin)) - finally: - self._kill(fin) - self._kill(fout) - - def test_decode(self): - try: - f = open(self.tmpin, 'wb') - f.write(encodedtextwrapped % (0644, self.tmpout)) - f.close() - - f = open(self.tmpin, 'rb') - uu.decode(f) - f.close() - #This was using rU but Jython lacks universal newline support - #See http://jython.org/bugs/1755361 - f = open(self.tmpout, 'r') - s = f.read() - f.close() - self.assertEqual(s, plaintext) - # XXX is there an xp way to verify the mode? - finally: - self._kill(f) - - def test_decodetwice(self): - # Verify that decode() will refuse to overwrite an existing file - try: - f = cStringIO.StringIO(encodedtextwrapped % (0644, self.tmpout)) - - f = open(self.tmpin, 'rb') - uu.decode(f) - f.close() - - f = open(self.tmpin, 'rb') - self.assertRaises(uu.Error, uu.decode, f) - f.close() - finally: - self._kill(f) - -def test_main(): - test_support.run_unittest(UUTest, UUStdIOTest, UUFileTest) - -if __name__=="__main__": - test_main() Modified: trunk/jython/src/org/python/core/PyFile.java =================================================================== --- trunk/jython/src/org/python/core/PyFile.java 2007-09-21 20:13:18 UTC (rev 3493) +++ trunk/jython/src/org/python/core/PyFile.java 2007-09-22 00:01:20 UTC (rev 3494) @@ -11,6 +11,8 @@ import java.io.RandomAccessFile; import java.io.Writer; +import java.util.EnumSet; +import java.util.Iterator; import java.util.LinkedList; // To do: @@ -36,6 +38,7 @@ dict.__setitem__("mode",new PyGetSetDescr("mode",PyFile.class,"getMode",null,null)); dict.__setitem__("name",new PyGetSetDescr("name",PyFile.class,"getName",null,null)); dict.__setitem__("closed",new PyGetSetDescr("closed",PyFile.class,"getClosed",null,null)); + dict.__setitem__("newlines",new PyGetSetDescr("newlines",PyFile.class,"getNewlines",null,null)); class exposed___cmp__ extends PyBuiltinMethodNarrow { exposed___cmp__(PyObject self,PyBuiltinFunction.Info info) { @@ -507,6 +510,9 @@ private FileWrapper file; + private boolean universal = false; + private boolean binary = false; + private Closer closer; private static LinkedList closers = new LinkedList(); static { @@ -519,7 +525,7 @@ private static InputStream _pb(InputStream s, String mode) { - if (mode.indexOf('b') < 0) { + if (mode.contains("b")) { if (s instanceof PushbackInputStream) { return s; } @@ -546,19 +552,17 @@ super(subType); } - public PyFile(FileWrapper file, String name, String mode) { - file_init(file, name, mode); - } - private void file_init(FileWrapper file, String name, String mode) { file.setMode(mode); this.name = name; this.mode = mode; this.softspace = false; this.closed = false; - if (mode.indexOf('b') < 0) { + if (binary) { this.file = new TextWrapper(file); - }else{ + } else if (universal) { + this.file = new UniversalWrapper(file); + } else { this.file = file; } } @@ -566,7 +570,7 @@ public PyFile(InputStream istream, OutputStream ostream, String name, String mode) { - this(new IOStreamWrapper(_pb(istream, mode), ostream), name, mode); + file_init(new IOStreamWrapper(_pb(istream, mode), ostream), name, mode); } public PyFile(InputStream istream, OutputStream ostream, String name) @@ -579,7 +583,7 @@ } public PyFile(InputStream istream, String name, String mode) { - this(new InputStreamWrapper(_pb(istream, mode)), name, mode); + file_init(new InputStreamWrapper(_pb(istream, mode)), name, mode); } public PyFile(InputStream istream, String name) { @@ -591,7 +595,7 @@ } public PyFile(OutputStream ostream, String name, String mode) { - this(new OutputStreamWrapper(ostream), name, mode); + file_init(new OutputStreamWrapper(ostream), name, mode); } public PyFile(OutputStream ostream, String name) { @@ -603,7 +607,7 @@ } public PyFile(Writer ostream, String name, String mode) { - this(new WriterWrapper(ostream), name, mode); + file_init(new WriterWrapper(ostream), name, mode); } public PyFile(Writer ostream, String name) { @@ -615,7 +619,7 @@ } public PyFile(RandomAccessFile file, String name, String mode) { - this(new RFileWrapper(file), name, mode); + file_init(new RFileWrapper(file), name, mode); } public PyFile(RandomAccessFile file, String name) { @@ -627,7 +631,7 @@ } public PyFile(String name, String mode, int bufsize) { - this(_setup(name, mode, bufsize), name, mode); + file_init(_setup(name, mode, bufsize), name, mode); } public void __setattr__(String name, PyObject value) { @@ -650,34 +654,14 @@ return o; } - private static FileWrapper _setup(String name, String mode, int bufsize) { - char c1 = ' '; - char c2 = ' '; - char c3 = ' '; - int n = mode.length(); - for (int i = 0; i < n; i++) { - if ("awrtb+".indexOf(mode.charAt(i)) < 0) - throw Py.IOError("Unknown open mode:" + mode); - } - if (n > 0) { - c1 = mode.charAt(0); - if (n > 1) { - c2 = mode.charAt(1); - if (n > 2) - c3 = mode.charAt(2); - } - } - String jmode = "r"; - if (c1 == 'r') { - if (c2 == '+' || c3 == '+') jmode = "rw"; - else jmode = "r"; - } - else if (c1 == 'w' || c1 == 'a') jmode = "rw"; + private FileWrapper _setup(String name, String mode, int bufsize) { + String jmode = sanitizeMode(mode); + char c1 = mode.charAt(0); try { File f = new File(name); if (c1 == 'r') { if (!f.exists()) { - throw new IOException("No such file or directory: " + name); + throw Py.IOError("No such file or directory: '" + name + "'"); } } if (c1 == 'w') { @@ -698,6 +682,46 @@ } } + /** + * Parse and validate the python file mode, returning a cleaned + * file mode suitable for RandomAccessFile + * + * @param mode a python file mode String + * @return a RandomAccessFile mode String + */ + private String sanitizeMode(String mode) { + if (mode.length() == 0) { + throw Py.IOError("invalid mode: "); + } + + String origMode = mode; + if (mode.contains("U")) { + universal = true; + mode = mode.replace("U", ""); + if (mode.length() == 0) { + mode = "r"; + } else if ("wa+".indexOf(mode.charAt(0)) > -1) { + throw Py.ValueError("universal newline mode can only be used with " + + "modes starting with 'r'"); + } + } + if ("rwa".indexOf(mode.charAt(0)) == -1) { + throw Py.ValueError("mode string must begin with one of 'r', 'w', 'a' or " + + "'U', not '" + origMode + "'"); + } + + binary = mode.indexOf('b') > -1; + + String cleanMode; + if ("wa".indexOf(mode.charAt(0)) > -1 || (mode.length() > 1 && + mode.charAt(1) == '+')) { + cleanMode = "rw"; + } else { + cleanMode = "r"; + } + return cleanMode; + } + final String file_read(int n) { if (closed) err_closed(); @@ -1009,6 +1033,29 @@ return closed; } + public PyObject getNewlines() { + if (!universal) { + return Py.None; + } + EnumSet newlineTypes = ((UniversalWrapper)file).getNewlineTypes(); + int size = newlineTypes.size(); + if (size == 0) { + return Py.None; + } else if (size == 1) { + String newline = ((Newline)newlineTypes.iterator().next()).getValue(); + return new PyString(newline); + } + + PyObject[] newlines = new PyObject[size]; + int i = 0; + for (Iterator newlineIter = newlineTypes.iterator(); newlineIter.hasNext();) { + String newline = ((Newline)newlineIter.next()).getValue(); + newlines[i] = new PyString(newline); + i++; + } + return new PyTuple(newlines); + } + protected void finalize() throws Throwable { super.finalize(); if (closer != null) { @@ -1499,10 +1546,14 @@ public TextWrapper(FileWrapper file) { this.file = file; sep = System.getProperty("line.separator"); - sep_is_nl = (sep == "\n"); + sep_is_nl = sep.equals("\n"); } public String read(int n) throws IOException { + if (sep_is_nl) { + return this.file.read(n); + } + // Convert CRLF to LF String s = this.file.read(n); int index = s.indexOf('\r'); if (index < 0) @@ -1512,10 +1563,13 @@ int end = s.length(); do { buf.append(s.substring(start, index)); - buf.append('\n'); - start = index + 1; - if (start < end && s.charAt(start) == '\n') - start++; + if (index < end - 1 && s.charAt(index + 1) == '\n') { + buf.append('\n'); + start = index + 2; + } else { + buf.append('\r'); + start = index + 1; + } index = s.indexOf('\r', start); } while (index >= 0); buf.append(s.substring(start)); @@ -1523,19 +1577,24 @@ int c = file.read(); if (c != -1 && c != '\n') file.unread(c); + else if (c == '\n') + buf.setCharAt(buf.length() - 1, '\n'); } return buf.toString(); } public int read() throws IOException { int c = file.read(); - if (c != '\r') + if (sep_is_nl || c != '\r' || file.available() == 0) { return c; - if (file.available() > 0) { - c = file.read(); - if (c != -1 && c != '\n') - file.unread(c); } + c = file.read(); + if (c == -1) { + return '\r'; + } else if (c != '\n') { + file.unread(c); + return '\r'; + } return '\n'; } @@ -1583,7 +1642,123 @@ } } + private static class UniversalWrapper extends FileWrapper { + /** The wrapped FileWrapper */ + private FileWrapper file; + + /** Whether the next character, if it's a LF, should be + * skipped (the previous character was a CR) */ + private boolean skipNextLF = false; + + /** The Newlines encountered in the current file */ + private EnumSet newlineTypes = EnumSet.noneOf(Newline.class); + + public UniversalWrapper(FileWrapper file) { + this.file = file; + } + + public String read(int n) throws IOException { + boolean all = n < 0; + StringBuffer sb = new StringBuffer(all ? 8192 : n); + while (all || n-- > 0) { + int next = read(); + if (next == -1) { + break; + } + sb.append((char)next); + } + return sb.toString(); + } + + public int read() throws IOException { + int c = file.read(); + switch (c) { + case '\r': + skipNextLF = true; + c = '\n'; + break; + case '\n': + if (skipNextLF) { + skipNextLF = false; + newlineTypes.add(Newline.CRLF); + c = read(); + break; + } + newlineTypes.add(Newline.LF); + break; + default: + if (skipNextLF) { + skipNextLF = false; + newlineTypes.add(Newline.CR); + } + } + return c; + } + + public void write(String s) throws IOException { + file.write(s); + } + + public long tell() throws IOException { + long pos = file.tell(); + if (skipNextLF) { + // Attempt to consume the next LF so the file position + // begins on the actual next line + int next = file.read(); + if ((char)next == '\n') { + pos++; + skipNextLF = false; + newlineTypes.add(Newline.CRLF); + } else if (next != -1) { + // Not a CRLF; rewind unless EOF + file.seek(file.tell() -1, 0); + } + } + return pos; + } + + public void seek(long pos, int how) throws IOException { + file.seek(pos, how); + } + + public void flush() throws IOException { + file.flush(); + } + + public void close() throws IOException { + file.close(); + } + + public void truncate(long position) throws IOException { + file.truncate(position); + } + + public Object __tojava__(Class cls) throws IOException { + return file.__tojava__(cls); + } + + public EnumSet getNewlineTypes() { + return newlineTypes; + } + } + /** + * Newline types + */ + public enum Newline { + CR ("\r"), + LF ("\n"), + CRLF ("\r\n"); + + private final String value; + public String getValue() { return value; } + + Newline(String value) { + this.value = value; + } + }; + + /** * A mechanism to make sure PyFiles are closed on exit. On * creation Closer adds itself to a list of Closers that will be * run by PyFileCloser on JVM shutdown. When a PyFile's close or @@ -1645,4 +1820,5 @@ } } } + } Modified: trunk/jython/src/templates/file.expose =================================================================== --- trunk/jython/src/templates/file.expose 2007-09-21 20:13:18 UTC (rev 3493) +++ trunk/jython/src/templates/file.expose 2007-09-22 00:01:20 UTC (rev 3494) @@ -6,6 +6,7 @@ expose_getset: mode getMode expose_getset: name getName expose_getset: closed getClosed +expose_getset: newlines getNewlines # exposed methods expose_vanilla_cmp expose_meth: __iter__ This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <pj...@us...> - 2007-09-22 05:20:30
|
Revision: 3498 http://jython.svn.sourceforge.net/jython/?rev=3498&view=rev Author: pjenvey Date: 2007-09-21 22:20:26 -0700 (Fri, 21 Sep 2007) Log Message: ----------- have str subclasses return a new string instead of themselves during str(subtype). fixes a pickling issue triggered by test_subclasses patch #1773865 thanks mehendran Modified Paths: -------------- trunk/jython/Lib/test/test_subclasses.py trunk/jython/src/org/python/core/PyString.java Modified: trunk/jython/Lib/test/test_subclasses.py =================================================================== --- trunk/jython/Lib/test/test_subclasses.py 2007-09-22 04:15:04 UTC (rev 3497) +++ trunk/jython/Lib/test/test_subclasses.py 2007-09-22 05:20:26 UTC (rev 3498) @@ -190,10 +190,6 @@ def test_main(): -# Jython transition 2.3 -# pickle fails on subclasses of builtin types -# http://jython.org/bugs/1768990 - del TestSubclasses.test_pickle_builtins test_support.run_unittest(TestSubclasses) if __name__ == "__main__": Modified: trunk/jython/src/org/python/core/PyString.java =================================================================== --- trunk/jython/src/org/python/core/PyString.java 2007-09-22 04:15:04 UTC (rev 3497) +++ trunk/jython/src/org/python/core/PyString.java 2007-09-22 05:20:26 UTC (rev 3498) @@ -1595,7 +1595,7 @@ if(S == null) { return new PyString(""); } - return S.__str__(); + return new PyString(S.__str__().toString()); } else { if (S == null) { return new PyStringDerived(subtype, ""); This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <cg...@us...> - 2007-09-22 10:35:00
|
Revision: 3501 http://jython.svn.sourceforge.net/jython/?rev=3501&view=rev Author: cgroves Date: 2007-09-22 03:34:58 -0700 (Sat, 22 Sep 2007) Log Message: ----------- Respect the cachedir setting for scanning packages when adding a jar to sys.path, and if it does need to be scanned, cache the results. Use Py.findClass rather than the context classloader to lookup classes in JavaImportHelper. This makes classes in jars on sys.path and the current PySystemState classloader available without package scanning in addition to those in the context classloader. Modified Paths: -------------- trunk/jython/bugtests/support.py trunk/jython/bugtests/test385.py trunk/jython/src/org/python/core/JavaImportHelper.java trunk/jython/src/org/python/core/PySystemState.java trunk/jython/src/org/python/core/SyspathArchive.java Added Paths: ----------- trunk/jython/bugtests/jarmaker.py trunk/jython/bugtests/simplejar/ trunk/jython/bugtests/simplejar/javapackage/ trunk/jython/bugtests/simplejar/javapackage/JavaClass.java trunk/jython/bugtests/test402.py trunk/jython/bugtests/test402m.py trunk/jython/bugtests/test402n.py Added: trunk/jython/bugtests/jarmaker.py =================================================================== --- trunk/jython/bugtests/jarmaker.py (rev 0) +++ trunk/jython/bugtests/jarmaker.py 2007-09-22 10:34:58 UTC (rev 3501) @@ -0,0 +1,24 @@ +import support +import sys +import os + +from java.io import File + +package = "javapackage" +clazz = "JavaClass" +jardir = "simplejar" +jarfn = "simple.jar" +clazzfile = File(jardir + '/'+ package, "%s.class" % clazz) # java.io.File + +def mkjar(): + jarfile = File(jardir, jarfn) + # create a .jar file containing a .class file + if not jarfile.exists(): + support.compileJava("%s/%s/%s.java" % (jardir, package, clazz)) + jarPacker = support.JarPacker(jarfile, bufsize=128) + jarPacker.addFile(clazzfile, parentDirName=package) + jarPacker.close() + return jardir + '/' + jarfn, package, clazz + + + Added: trunk/jython/bugtests/simplejar/javapackage/JavaClass.java =================================================================== --- trunk/jython/bugtests/simplejar/javapackage/JavaClass.java (rev 0) +++ trunk/jython/bugtests/simplejar/javapackage/JavaClass.java 2007-09-22 10:34:58 UTC (rev 3501) @@ -0,0 +1,3 @@ +package javapackage; + +public class JavaClass {} Modified: trunk/jython/bugtests/support.py =================================================================== --- trunk/jython/bugtests/support.py 2007-09-22 06:27:09 UTC (rev 3500) +++ trunk/jython/bugtests/support.py 2007-09-22 10:34:58 UTC (rev 3501) @@ -108,13 +108,16 @@ return execCmd(cmd, kw) def runJython(cls, **kw): + javaargs = '' + if 'javaargs' in kw: + javaargs = kw['javaargs'] classpath = cfg.classpath if "classpath" in kw: classpath = os.pathsep.join([cfg.classpath, kw["classpath"]]) if UNIX: - cmd = "%s/bin/java -classpath %s -Dpython.home=%s org.python.util.jython %s" % (cfg.java_home, classpath, cfg.jython_home, cls) + cmd = "%s/bin/java -classpath %s %s -Dpython.home=%s org.python.util.jython %s" % (cfg.java_home, classpath, javaargs, cfg.jython_home, cls) elif WIN: - cmd = 'cmd /C "%s/bin/java.exe -classpath %s -Dpython.home=%s org.python.util.jython %s"' % (cfg.java_home, classpath, cfg.jython_home, cls) + cmd = 'cmd /C "%s/bin/java.exe -classpath %s %s -Dpython.home=%s org.python.util.jython %s"' % (cfg.java_home, classpath, javaargs, cfg.jython_home, cls) return execCmd(cmd, kw) def compileJPythonc(*files, **kw): Modified: trunk/jython/bugtests/test385.py =================================================================== --- trunk/jython/bugtests/test385.py 2007-09-22 06:27:09 UTC (rev 3500) +++ trunk/jython/bugtests/test385.py 2007-09-22 10:34:58 UTC (rev 3501) @@ -9,54 +9,17 @@ use a unique java package name for the sake of this test """ +import jarmaker import support import sys -import os -from java.io import File - -PACKAGE = "test385javapackage" -CLAZZ = "test385j" -JARDIR = "test385jar" -JARFILE = "test385.jar" -CLAZZ_FILE = File(PACKAGE, "%s.class" % CLAZZ) # java.io.File - -def mkdir(dir): - if not os.path.exists(dir): - os.mkdir(dir) - -def mkjavaclass(): - mkdir(PACKAGE) - f = open("%s/%s.java" % (PACKAGE, CLAZZ), "w") - f.write(""" -package %s; -public class %s { -} -""" % (PACKAGE, CLAZZ)) - f.close() - support.compileJava("%s/%s.java" % (PACKAGE, CLAZZ)) - -def mkjar(): - mkdir(JARDIR) - jarFile = File(JARDIR, JARFILE) - jarPacker = support.JarPacker(jarFile, bufsize=128) - jarPacker.addFile(CLAZZ_FILE, parentDirName=PACKAGE) - jarPacker.close() - return jarFile - - -# create a .jar file containing a .class file -mkjavaclass() -jarFile = mkjar() - -# important: delete the class file from the file system (otherwise it can be imported) -CLAZZ_FILE.delete() -if CLAZZ_FILE.exists(): - raise AssertionError, "%s is still on the file system" % CLAZZ_FILE - +jarfn, package, clazz = jarmaker.mkjar() # append this jar file to sys.path -sys.path.append(jarFile.getAbsolutePath()) +sys.path.append(jarfn) # try to import the class -importStmt = "from %s import %s" % (PACKAGE, CLAZZ) -exec(importStmt) \ No newline at end of file +importStmt = "from %s import %s" % (package, clazz) +try: + exec(importStmt) +finally: + sys.path.remove(jarfn) Added: trunk/jython/bugtests/test402.py =================================================================== --- trunk/jython/bugtests/test402.py (rev 0) +++ trunk/jython/bugtests/test402.py 2007-09-22 10:34:58 UTC (rev 3501) @@ -0,0 +1,24 @@ +''' + +test402m adds a jar file to sys.path and imports a package from it. The first +run ensures that, by default, package scanning is enabled for jars added to +sys.path. The second run turns off package scanning, so it checks that the +package is unimportable without the scan. Finally, we run test402n which adds +the same jar to its sys.path and imports a fully qualified class from it. We +run it with package scanning off to make sure that even without package +scanning, jars are correctly added to sys.path and fully qualified class +imports work on them. + +''' + +import support +import jarmaker + +jarmaker.mkjar() + +support.runJython('test402m.py') +ret = support.runJython('test402m.py', error='test402.err', + javaargs='-Dpython.cachedir.skip=true', expectError=1) +if ret == 0: + raise support.TestError('Successfully imported a package from a jar on sys.path without caching!') +support.runJython('test402n.py', javaargs='-Dpython.cachedir.skip=true') Added: trunk/jython/bugtests/test402m.py =================================================================== --- trunk/jython/bugtests/test402m.py (rev 0) +++ trunk/jython/bugtests/test402m.py 2007-09-22 10:34:58 UTC (rev 3501) @@ -0,0 +1,4 @@ +import sys +sys.path.append('simplejar/simple.jar') + +import javapackage Added: trunk/jython/bugtests/test402n.py =================================================================== --- trunk/jython/bugtests/test402n.py (rev 0) +++ trunk/jython/bugtests/test402n.py 2007-09-22 10:34:58 UTC (rev 3501) @@ -0,0 +1,4 @@ +import sys +sys.path.append('simplejar/simple.jar') + +from javapackage import JavaClass Modified: trunk/jython/src/org/python/core/JavaImportHelper.java =================================================================== --- trunk/jython/src/org/python/core/JavaImportHelper.java 2007-09-22 06:27:09 UTC (rev 3500) +++ trunk/jython/src/org/python/core/JavaImportHelper.java 2007-09-22 10:34:58 UTC (rev 3501) @@ -176,20 +176,12 @@ } /** - * Check a java class on VM level. - * - * @param packageName - * @param className - * - * @return <code>true</code> if the java class can be doubtlessly identified, <code>false</code> otherwise. + * @return <code>true</code> if the java class can be found by the current + * Py classloader setup */ private static boolean isJavaClass(String packageName, String className) { - if (className != null && className.length() > 0) { - className = packageName.replace('.', '/') + "/" + className + ".class"; - return Thread.currentThread().getContextClassLoader().getResource(className) != null; - } else { - return false; - } + return className != null && className.length() > 0 + && Py.findClass(packageName + "." + className) != null; } /** Modified: trunk/jython/src/org/python/core/PySystemState.java =================================================================== --- trunk/jython/src/org/python/core/PySystemState.java 2007-09-22 06:27:09 UTC (rev 3500) +++ trunk/jython/src/org/python/core/PySystemState.java 2007-09-22 10:34:58 UTC (rev 3501) @@ -544,6 +544,10 @@ public static PackageManager packageManager; public static File cachedir; + + public static boolean isPackageCacheEnabled() { + return cachedir != null; + } private static void initCacheDirectory(Properties props) { if (Py.frozen) { Modified: trunk/jython/src/org/python/core/SyspathArchive.java =================================================================== --- trunk/jython/src/org/python/core/SyspathArchive.java 2007-09-22 06:27:09 UTC (rev 3500) +++ trunk/jython/src/org/python/core/SyspathArchive.java 2007-09-22 10:34:58 UTC (rev 3501) @@ -13,7 +13,9 @@ throw new IOException("path '" + archiveName + "' not an archive"); } this.zipFile = new ZipFile(new File(archiveName)); - PySystemState.packageManager.addJar(archiveName, false); + if(PySystemState.isPackageCacheEnabled()) { + PySystemState.packageManager.addJar(archiveName, true); + } } SyspathArchive(ZipFile zipFile, String archiveName) { This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <cg...@us...> - 2007-09-22 11:15:33
|
Revision: 3503 http://jython.svn.sourceforge.net/jython/?rev=3503&view=rev Author: cgroves Date: 2007-09-22 04:15:23 -0700 (Sat, 22 Sep 2007) Log Message: ----------- Call __str__ on unicode objects passed to file.write so they'll be encoded for writing. Modified Paths: -------------- trunk/jython/bugtests/test207.py trunk/jython/src/org/python/core/PyFile.java trunk/jython/src/templates/file.expose Modified: trunk/jython/bugtests/test207.py =================================================================== --- trunk/jython/bugtests/test207.py 2007-09-22 10:37:34 UTC (rev 3502) +++ trunk/jython/bugtests/test207.py 2007-09-22 11:15:23 UTC (rev 3503) @@ -1,28 +1,34 @@ """ - +Test that file writing doesn't attempt to encode things by default and reading +doesn't decode things by default. """ import support +EURO_SIGN = u"\u20ac" +try: + EURO_SIGN.encode() + import sys + raise support.TestError('Your default encoding, %s, can handle encoding the Euro sign. This test needs the default encoding to be unable to handle on its test character' % + sys.getdefaultencoding()) +except UnicodeEncodeError: + pass + f = open("test207.out", "w") -f.write(u"\u20ac") +try: + f.write(EURO_SIGN) + raise support.TestError("Shouldn't be able to write out a Euro sign without first encoding") +except UnicodeEncodeError: + pass f.close() -f = open("test207.out", "r") -if ord(f.read()) != 0x20AC: - raise support.TestError("EURO sign didn\xF8t survive a text file") +f = open("test207.out", "w") +f.write(EURO_SIGN.encode('utf-8')) f.close() - - -f = open("test207.out", "wb") -f.write(u"\u20ac") +f = open("test207.out", "r") +encoded_euro = f.read() f.close() - -f = open("test207.out", "rb") -if ord(f.read()) != 0xAC: - raise support.TestError("EURO sign should have been truncated.") +if encoded_euro != '\xe2\x82\xac' or encoded_euro.decode('utf-8') != EURO_SIGN: + raise support.TestError("Read something other than the euro sign that we wrote out") f.close() - - -#raise support.TestError("" + `x`) Modified: trunk/jython/src/org/python/core/PyFile.java =================================================================== --- trunk/jython/src/org/python/core/PyFile.java 2007-09-22 10:37:34 UTC (rev 3502) +++ trunk/jython/src/org/python/core/PyFile.java 2007-09-22 11:15:23 UTC (rev 3503) @@ -395,20 +395,8 @@ } public PyObject __call__(PyObject arg0) { - try { - ((PyFile)self).file_write(arg0.asString(0)); + ((PyFile)self).file_write(arg0); return Py.None; - } catch (PyObject.ConversionException e) { - String msg; - switch (e.index) { - case 0: - msg="expected a string"; - break; - default: - msg="xxx"; - } - throw Py.TypeError(msg); - } } } @@ -858,6 +846,17 @@ return file_xreadlines(); } + final void file_write(PyObject o) { + if(o instanceof PyUnicode) { + // Call __str__ on unicode objects to encode them before writing + file_write(o.__str__().string); + } else if(o instanceof PyString) { + file_write(((PyString)o).string); + } else { + throw Py.TypeError("write requires a string as its argument"); + } + } + final void file_write(String s) { if (closed) err_closed(); Modified: trunk/jython/src/templates/file.expose =================================================================== --- trunk/jython/src/templates/file.expose 2007-09-22 10:37:34 UTC (rev 3502) +++ trunk/jython/src/templates/file.expose 2007-09-22 11:15:23 UTC (rev 3503) @@ -25,7 +25,7 @@ expose_meth: :l tell expose_meth: :o next expose_meth: :- truncate l? -expose_meth: :- write s +expose_meth: :- write o expose_meth: :- writelines o expose_meth: :o xreadlines expose_wide_meth: __init__ -1 -1 This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <cg...@us...> - 2007-09-22 18:57:13
|
Revision: 3509 http://jython.svn.sourceforge.net/jython/?rev=3509&view=rev Author: cgroves Date: 2007-09-22 11:57:08 -0700 (Sat, 22 Sep 2007) Log Message: ----------- Patch #1772858 from ayesha to fix bug #1768074: str.replace doesn't allow an empty replacement string Modified Paths: -------------- trunk/jython/Lib/test/string_tests.py trunk/jython/src/org/python/core/PyString.java Modified: trunk/jython/Lib/test/string_tests.py =================================================================== --- trunk/jython/Lib/test/string_tests.py 2007-09-22 12:09:08 UTC (rev 3508) +++ trunk/jython/Lib/test/string_tests.py 2007-09-22 18:57:08 UTC (rev 3509) @@ -261,13 +261,10 @@ self.checkequal('one@two@three@', 'one!two!three!', 'replace', '!', '@') self.checkequal('one!two!three!', 'one!two!three!', 'replace', 'x', '@') self.checkequal('one!two!three!', 'one!two!three!', 'replace', 'x', '@', 2) -# Jython transition 2.3 -# str.replace doesn't handle an empty string to be replaced. -# http://jython.org/bugs/1768074 -# self.checkequal('-a-b-c-', 'abc', 'replace', '', '-') -# self.checkequal('-a-b-c', 'abc', 'replace', '', '-', 3) -# self.checkequal('abc', 'abc', 'replace', '', '-', 0) -# self.checkequal('', '', 'replace', '', '') + self.checkequal('-a-b-c-', 'abc', 'replace', '', '-') + self.checkequal('-a-b-c', 'abc', 'replace', '', '-', 3) + self.checkequal('abc', 'abc', 'replace', '', '-', 0) + self.checkequal('', '', 'replace', '', '') self.checkequal('abc', 'abc', 'replace', 'ab', '--', 0) self.checkequal('abc', 'abc', 'replace', 'xy', '--') # Next three for SF bug 422088: [OSF1 alpha] string.replace(); died with Modified: trunk/jython/src/org/python/core/PyString.java =================================================================== --- trunk/jython/src/org/python/core/PyString.java 2007-09-22 12:09:08 UTC (rev 3508) +++ trunk/jython/src/org/python/core/PyString.java 2007-09-22 18:57:08 UTC (rev 3509) @@ -2625,23 +2625,27 @@ } private PyList splitfields(String sep, int maxsplit) { - if (sep.length() == 0) { - throw Py.ValueError("empty separator"); - } - PyList list = new PyList(); int length = string.length(); if (maxsplit < 0) - maxsplit = length; + maxsplit = length + 1; int lastbreak = 0; int splits = 0; int sepLength = sep.length(); + int index; + if((sep.length() == 0) && (maxsplit != 0)) { + index = string.indexOf(sep, lastbreak); + list.append(fromSubstring(lastbreak, index)); + splits++; + } while (splits < maxsplit) { - int index = string.indexOf(sep, lastbreak); + index = string.indexOf(sep, lastbreak); if (index == -1) break; + if(sep.length() == 0) + index++; splits += 1; list.append(fromSubstring(lastbreak, index)); lastbreak = index + sepLength; @@ -3127,13 +3131,23 @@ } final PyString str_replace(PyObject oldPiece, PyObject newPiece) { - return str_replace(oldPiece, newPiece, string.length()); + if(!(oldPiece instanceof PyString)) { + throw Py.TypeError("str or unicode required for replace"); + } + if(oldPiece.__len__() == 0) { + return str_replace(oldPiece, newPiece, string.length() + 1); + } else { + return str_replace(oldPiece, newPiece, string.length()); + } } final PyString str_replace(PyObject oldPiece, PyObject newPiece, int maxsplit) { if(!(oldPiece instanceof PyString) || !(newPiece instanceof PyString)){ throw Py.TypeError("str or unicode required for replace"); } + if(string.length() == 0) { + return new PyString(string); + } return ((PyString)newPiece).str_join(str_split(((PyString)oldPiece).string, maxsplit)); } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <pj...@us...> - 2007-09-24 05:58:58
|
Revision: 3524 http://jython.svn.sourceforge.net/jython/?rev=3524&view=rev Author: pjenvey Date: 2007-09-23 22:58:54 -0700 (Sun, 23 Sep 2007) Log Message: ----------- fix javashell not handling unicode commands correctly, with tests fixes bug #1735774 thanks Pekka Laukkanen Modified Paths: -------------- trunk/jython/Lib/javashell.py trunk/jython/Lib/test/test_javashell.py trunk/jython/NEWS Modified: trunk/jython/Lib/javashell.py =================================================================== --- trunk/jython/Lib/javashell.py 2007-09-24 01:33:00 UTC (rev 3523) +++ trunk/jython/Lib/javashell.py 2007-09-24 05:58:54 UTC (rev 3524) @@ -75,7 +75,7 @@ " setting %s. Failed command=%s""" raise OSError( 0, msgFmt % ( _osType, _envType, cmd )) - if isinstance(cmd, types.StringType): + if isinstance(cmd, basestring): shellCmd = self.cmd + [cmd] else: shellCmd = cmd Modified: trunk/jython/Lib/test/test_javashell.py =================================================================== --- trunk/jython/Lib/test/test_javashell.py 2007-09-24 01:33:00 UTC (rev 3523) +++ trunk/jython/Lib/test/test_javashell.py 2007-09-24 05:58:54 UTC (rev 3524) @@ -163,6 +163,17 @@ newValue, value )) + def testFormatUnicodeCommand(self): + shell = javashell._ShellEnv(cmd=['runner']) + self.assertEqual(shell._formatCmd('echo hello'), ['runner', 'echo hello']) + self.assertEqual(shell._formatCmd(u'echo world'), ['runner', u'echo world']) + + def testExecuteUnicodeCommandWithRedirection(self): + process = javashell.shellexecute(u'nonexcmd 2>&1') + stdout = process.getOutputStream().toString() + process.waitFor() + self.assertNotEqual(stdout, "", "Redirecting 2>&1 failed with unicode cmd") + def test_main(): test_support.run_unittest(JavaShellTest) Modified: trunk/jython/NEWS =================================================================== --- trunk/jython/NEWS 2007-09-24 01:33:00 UTC (rev 3523) +++ trunk/jython/NEWS 2007-09-24 05:58:54 UTC (rev 3524) @@ -14,6 +14,7 @@ - [ 1799328 ] string formatting doesn't call __unicode__ on %s in unicode objects - [ 1763263 ] os.utime(path, None) doesn't work (incl. a patch) - [ 1758904 ] I added doc strings for functions in os module (javaos.py). + - [ 1735774 ] Redirecting stdout/err with os.popen fails if cmd is unicode Jython 2.2 No changes from 2.2 rc3 This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <cg...@us...> - 2007-09-25 04:36:43
|
Revision: 3541 http://jython.svn.sourceforge.net/jython/?rev=3541&view=rev Author: cgroves Date: 2007-09-24 21:36:38 -0700 (Mon, 24 Sep 2007) Log Message: ----------- Add sys.exc_clear. Patch #1771534 from ukeshav for bug #1768982 Modified Paths: -------------- trunk/jython/Lib/test/test_sys.py trunk/jython/src/org/python/core/PySystemState.java Modified: trunk/jython/Lib/test/test_sys.py =================================================================== --- trunk/jython/Lib/test/test_sys.py 2007-09-25 04:26:09 UTC (rev 3540) +++ trunk/jython/Lib/test/test_sys.py 2007-09-25 04:36:38 UTC (rev 3541) @@ -259,10 +259,6 @@ del SysModuleTest.test_lost_displayhook del SysModuleTest.test_refcount del SysModuleTest.test_setcheckinterval -# Jython transition 2.3 -# sys.exc_clear is missing -# http://jython.org/bugs/1768982 - del SysModuleTest.test_exc_clear test.test_support.run_unittest(SysModuleTest) if __name__ == "__main__": Modified: trunk/jython/src/org/python/core/PySystemState.java =================================================================== --- trunk/jython/src/org/python/core/PySystemState.java 2007-09-25 04:26:09 UTC (rev 3540) +++ trunk/jython/src/org/python/core/PySystemState.java 2007-09-25 04:36:38 UTC (rev 3541) @@ -150,6 +150,10 @@ exc.traceback}); } + public static void exc_clear() { + Py.getThreadState().exception = null; + } + public static PyFrame _getframe() { return _getframe(-1); } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <pj...@us...> - 2007-09-27 04:57:39
|
Revision: 3546 http://jython.svn.sourceforge.net/jython/?rev=3546&view=rev Author: pjenvey Date: 2007-09-26 21:57:24 -0700 (Wed, 26 Sep 2007) Log Message: ----------- ensure universal newlines' seek doesn't confuse CRLF newline identification Modified Paths: -------------- trunk/jython/Lib/test/test_file_newlines.py trunk/jython/src/org/python/core/PyFile.java Modified: trunk/jython/Lib/test/test_file_newlines.py =================================================================== --- trunk/jython/Lib/test/test_file_newlines.py 2007-09-25 23:14:25 UTC (rev 3545) +++ trunk/jython/Lib/test/test_file_newlines.py 2007-09-27 04:57:24 UTC (rev 3546) @@ -141,6 +141,14 @@ readline(self.fp, 'CRLF\n', 5) readline(self.fp, 'EOF', 3) + def test_seek(self): + # Ensure seek doesn't confuse CRLF newline identification + self.fp.seek(6) + readline(self.fp, 'CRLF\n') + assert self.fp.newlines == None + self.fp.seek(5) + readline(self.fp, '\n') + assert self.fp.newlines == '\n' class WriteUniversalNewlinesTestCase(unittest.TestCase): Modified: trunk/jython/src/org/python/core/PyFile.java =================================================================== --- trunk/jython/src/org/python/core/PyFile.java 2007-09-25 23:14:25 UTC (rev 3545) +++ trunk/jython/src/org/python/core/PyFile.java 2007-09-27 04:57:24 UTC (rev 3546) @@ -1702,6 +1702,7 @@ public void seek(long pos, int how) throws IOException { file.seek(pos, how); + skipNextLF = false; } public void flush() throws IOException { This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <cg...@us...> - 2007-10-06 05:28:18
|
Revision: 3572 http://jython.svn.sourceforge.net/jython/?rev=3572&view=rev Author: cgroves Date: 2007-10-05 22:28:17 -0700 (Fri, 05 Oct 2007) Log Message: ----------- Patch #1789137 from leosoto for bug #1781500, metaclasses don't get passed a '__module__' in attrs Modified Paths: -------------- trunk/jython/src/org/python/core/Py.java Added Paths: ----------- trunk/jython/Lib/test/test_metaclass.py trunk/jython/Lib/test/test_metaclass_support/ trunk/jython/Lib/test/test_metaclass_support/__init__.py trunk/jython/Lib/test/test_metaclass_support/metaclass.py trunk/jython/Lib/test/test_metaclass_support/simpleclass.py Added: trunk/jython/Lib/test/test_metaclass.py =================================================================== --- trunk/jython/Lib/test/test_metaclass.py (rev 0) +++ trunk/jython/Lib/test/test_metaclass.py 2007-10-06 05:28:17 UTC (rev 3572) @@ -0,0 +1,14 @@ +import unittest +from test import test_support + +class MetaclassModuleTestCase(unittest.TestCase): + def test_module_attribute(self): + #Test for SF bug #1781500: wrong __module__ for classes with a metaclass + from test_metaclass_support.simpleclass import TestClass + self.assert_(TestClass.__module__.endswith('simpleclass')) + +def test_main(): + test_support.run_unittest(MetaclassModuleTestCase) + +if __name__ == '__main__': + test_main() Added: trunk/jython/Lib/test/test_metaclass_support/__init__.py =================================================================== --- trunk/jython/Lib/test/test_metaclass_support/__init__.py (rev 0) +++ trunk/jython/Lib/test/test_metaclass_support/__init__.py 2007-10-06 05:28:17 UTC (rev 3572) @@ -0,0 +1 @@ +# Support files for test.test_class Added: trunk/jython/Lib/test/test_metaclass_support/metaclass.py =================================================================== --- trunk/jython/Lib/test/test_metaclass_support/metaclass.py (rev 0) +++ trunk/jython/Lib/test/test_metaclass_support/metaclass.py 2007-10-06 05:28:17 UTC (rev 3572) @@ -0,0 +1,5 @@ +class NoOpMetaClass(type): + "A no-op meta class, useful for testing the SF bug #1781500" + def __new__(cls, name, bases, attrs): + r = type.__new__(cls, name, bases, attrs) + return r Added: trunk/jython/Lib/test/test_metaclass_support/simpleclass.py =================================================================== --- trunk/jython/Lib/test/test_metaclass_support/simpleclass.py (rev 0) +++ trunk/jython/Lib/test/test_metaclass_support/simpleclass.py 2007-10-06 05:28:17 UTC (rev 3572) @@ -0,0 +1,4 @@ +from metaclass import NoOpMetaClass +class TestClass(object): + __metaclass__ = NoOpMetaClass + Modified: trunk/jython/src/org/python/core/Py.java =================================================================== --- trunk/jython/src/org/python/core/Py.java 2007-10-06 05:26:54 UTC (rev 3571) +++ trunk/jython/src/org/python/core/Py.java 2007-10-06 05:28:17 UTC (rev 3572) @@ -1622,8 +1622,16 @@ PyObject dict = code.call(Py.EmptyObjects, Py.NoKeywords, globals, Py.EmptyObjects, new PyTuple(closure_cells)); - if (doc != null) + if (doc != null) { dict.__setitem__("__doc__", doc); + } + + if(dict.__finditem__("__module__") == null) { + PyObject module = globals.__finditem__("__name__"); + if(module != null) { + dict.__setitem__("__module__", module); + } + } PyObject metaclass; This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <pj...@us...> - 2007-11-10 02:43:31
|
Revision: 3663 http://jython.svn.sourceforge.net/jython/?rev=3663&view=rev Author: pjenvey Date: 2007-11-09 18:43:29 -0800 (Fri, 09 Nov 2007) Log Message: ----------- Merged revisions 3648,3652 via svnmerge from https://jython.svn.sourceforge.net/svnroot/jython/branches/pyfile-nio ........ r3648 | pjenvey | 2007-11-05 20:35:50 -0800 (Mon, 05 Nov 2007) | 15 lines o replace usage of PyFile in socket.makefile with the pure python file-like socket._fileobject from CPython 2.4.4. fixes deadlocks with makefile objects, #1744567 o kill FileWrapper and move the file vs socket close() handling to the pure python _socketobject and _closedsocket wrappers (both adapted from CPython 2.4.4) and _fileobject o make file_count more of a reference_count. move it down into _nonblocking_api_mixin so file objects' close() works for UDP sockets. with a test o kill socket.SocketTypes now that socket._socketobject always wraps both _tcpsocket and _udpsocket ........ r3652 | pjenvey | 2007-11-06 12:38:30 -0800 (Tue, 06 Nov 2007) | 2 lines add a _socketobject passthrough for getchannel refs #1744567 ........ Modified Paths: -------------- trunk/jython/Lib/socket.py trunk/jython/Lib/test/test_socket.py Property Changed: ---------------- trunk/jython/ Property changes on: trunk/jython ___________________________________________________________________ Name: svnmerge-integrated - /branches/pyfile-nio:1-3647 + /branches/pyfile-nio:1-3648,3652 Modified: trunk/jython/Lib/socket.py =================================================================== --- trunk/jython/Lib/socket.py 2007-11-10 02:36:44 UTC (rev 3662) +++ trunk/jython/Lib/socket.py 2007-11-10 02:43:29 UTC (rev 3663) @@ -75,7 +75,6 @@ import java.nio.channels.UnsupportedAddressTypeException import javax.net.ssl.SSLSocketFactory -import org.python.core.PyFile class error(Exception): pass class herror(error): pass @@ -360,7 +359,7 @@ # Same situation as above raise NotImplementedError("getprotobyname not yet supported on jython.") -def socket(family = AF_INET, type = SOCK_STREAM, flags=0): +def _realsocket(family = AF_INET, type = SOCK_STREAM, flags=0): assert family == AF_INET assert type in (SOCK_DGRAM, SOCK_STREAM) assert flags == 0 @@ -409,6 +408,8 @@ timeout = _defaulttimeout mode = MODE_BLOCKING + reference_count = 0 + close_lock = threading.Lock() def gettimeout(self): return self.timeout @@ -464,7 +465,6 @@ ostream = None local_addr = None server = 0 - file_count = 0 reuse_addr = 0 def bind(self, addr): @@ -610,66 +610,6 @@ if optname == SO_REUSEADDR: return self.reuse_addr - def makefile(self, mode="r", bufsize=-1): - file = None - if self.istream: - if self.ostream: - file = org.python.core.PyFile(self.istream, self.ostream, - "<socket>", mode) - else: - file = org.python.core.PyFile(self.istream, "<socket>", mode) - elif self.ostream: - file = org.python.core.PyFile(self.ostream, "<socket>", mode) - else: - raise IOError, "both istream and ostream have been shut down" - if file: - return _tcpsocket.FileWrapper(self, file) - - class FileWrapper: - def __init__(self, socket, file): - self.socket = socket - self.istream = socket.istream - self.ostream = socket.ostream - - self.file = file - self.read = file.read - self.readline = file.readline - self.readlines = file.readlines - self.write = file.write - self.writelines = file.writelines - self.flush = file.flush - self.seek = file.seek - self.tell = file.tell - self.closed = file.closed - - self.socket.file_count += 1 - - def close(self): - if self.closed: - # Already closed - return - - self.socket.file_count -= 1 - # AMAK: 20070715: Cannot close the PyFile, because closing - # it causes the InputStream and OutputStream to be closed. - # This in turn causes the underlying socket to be closed. - # This was always true for java.net sockets - # And continues to be true for java.nio sockets - # http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4717638 -# self.file.close() - istream = self.istream - ostream = self.ostream - self.istream = None - self.ostream = None -# self.closed = self.file.closed - self.closed = 1 - - if self.socket.file_count == 0 and self.socket.sock_impl is None: - # This is the last file Only close the socket and streams - # if there are no outstanding files left. - istream.close() - ostream.close() - def shutdown(self, how): assert how in (SHUT_RD, SHUT_WR, SHUT_RDWR) assert self.sock_impl @@ -680,23 +620,12 @@ def close(self): try: - if not self.sock_impl: - return - sock_impl = self.sock_impl - istream = self.istream - ostream = self.ostream - self.sock_impl = None - self.istream = None - self.ostream = None - # Only close the socket and streams if there are no - # outstanding files left. - if self.file_count == 0: - if istream: - istream.close() - if ostream: - ostream.close() - if sock_impl: - sock_impl.close() + if self.istream: + self.istream.close() + if self.ostream: + self.ostream.close() + if self.sock_impl: + self.sock_impl.close() except java.lang.Exception, jlx: raise _map_exception(jlx) @@ -814,11 +743,8 @@ def close(self): try: - if not self.sock_impl: - return - sock = self.sock_impl - self.sock_impl = None - sock.close() + if self.sock_impl: + self.sock_impl.close() except java.lang.Exception, jlx: raise _map_exception(jlx) @@ -839,9 +765,323 @@ except java.lang.Exception, jlx: raise _map_exception(jlx) -SocketType = _tcpsocket -SocketTypes = [_tcpsocket, _udpsocket] +_socketmethods = ( + 'bind', 'connect', 'connect_ex', 'fileno', 'listen', + 'getpeername', 'getsockname', 'getsockopt', 'setsockopt', + 'sendall', 'setblocking', + 'settimeout', 'gettimeout', 'shutdown', 'getchannel') +class _closedsocket(object): + __slots__ = [] + def _dummy(*args): + raise error(errno.EBADF, 'Bad file descriptor') + send = recv = sendto = recvfrom = __getattr__ = _dummy + +class _socketobject(object): + + __doc__ = _realsocket.__doc__ + + __slots__ = ["_sock", "send", "recv", "sendto", "recvfrom", + "__weakref__"] + + def __init__(self, family=AF_INET, type=SOCK_STREAM, proto=0, _sock=None): + if _sock is None: + _sock = _realsocket(family, type, proto) + _sock.reference_count += 1 + elif not isinstance(_sock, _closedsocket): + _sock.reference_count += 1 + self._sock = _sock + self.send = self._sock.send + self.recv = self._sock.recv + if hasattr(self._sock, 'sendto'): + self.sendto = self._sock.sendto + self.recvfrom = self._sock.recvfrom + + def close(self): + _sock = self._sock + if not isinstance(_sock, _closedsocket): + _sock.close_lock.acquire() + try: + _sock.reference_count -=1 + if not _sock.reference_count: + _sock.close() + self._sock = _closedsocket() + self.send = self.recv = self.sendto = self.recvfrom = \ + self._sock._dummy + finally: + _sock.close_lock.release() + #close.__doc__ = _realsocket.close.__doc__ + + def accept(self): + sock, addr = self._sock.accept() + return _socketobject(_sock=sock), addr + #accept.__doc__ = _realsocket.accept.__doc__ + + def dup(self): + """dup() -> socket object + + Return a new socket object connected to the same system resource.""" + _sock = self._sock + if isinstance(_sock, _closedsocket): + return _socketobject(_sock=_sock) + + _sock.close_lock.acquire() + try: + duped = _socketobject(_sock=_sock) + finally: + _sock.close_lock.release() + return duped + + def makefile(self, mode='r', bufsize=-1): + """makefile([mode[, bufsize]]) -> file object + + Return a regular file object corresponding to the socket. The mode + and bufsize arguments are as for the built-in open() function.""" + _sock = self._sock + if isinstance(_sock, _closedsocket): + return _fileobject(_sock, mode, bufsize) + + _sock.close_lock.acquire() + try: + fileobject = _fileobject(_sock, mode, bufsize) + finally: + _sock.close_lock.release() + return fileobject + + _s = ("def %s(self, *args): return self._sock.%s(*args)\n\n" + #"%s.__doc__ = _realsocket.%s.__doc__\n") + ) + for _m in _socketmethods: + #exec _s % (_m, _m, _m, _m) + exec _s % (_m, _m) + del _m, _s + +socket = SocketType = _socketobject + +class _fileobject(object): + """Faux file object attached to a socket object.""" + + default_bufsize = 8192 + name = "<socket>" + + __slots__ = ["mode", "bufsize", "softspace", + # "closed" is a property, see below + "_sock", "_rbufsize", "_wbufsize", "_rbuf", "_wbuf", + "_close"] + + def __init__(self, sock, mode='rb', bufsize=-1): + self._sock = sock + if not isinstance(sock, _closedsocket): + sock.reference_count += 1 + self.mode = mode # Not actually used in this version + if bufsize < 0: + bufsize = self.default_bufsize + self.bufsize = bufsize + self.softspace = False + if bufsize == 0: + self._rbufsize = 1 + elif bufsize == 1: + self._rbufsize = self.default_bufsize + else: + self._rbufsize = bufsize + self._wbufsize = bufsize + self._rbuf = "" # A string + self._wbuf = [] # A list of strings + + def _getclosed(self): + return self._sock is None + closed = property(_getclosed, doc="True if the file is closed") + + def close(self): + try: + if self._sock: + self.flush() + finally: + if self._sock and not isinstance(self._sock, _closedsocket): + self._sock.reference_count -= 1 + if not self._sock.reference_count: + self._sock.close() + self._sock = None + + def __del__(self): + try: + self.close() + except: + # close() may fail if __init__ didn't complete + pass + + def flush(self): + if self._wbuf: + buffer = "".join(self._wbuf) + self._wbuf = [] + self._sock.sendall(buffer) + + def fileno(self): + return self._sock.fileno() + + def write(self, data): + data = str(data) # XXX Should really reject non-string non-buffers + if not data: + return + self._wbuf.append(data) + if (self._wbufsize == 0 or + self._wbufsize == 1 and '\n' in data or + self._get_wbuf_len() >= self._wbufsize): + self.flush() + + def writelines(self, list): + # XXX We could do better here for very long lists + # XXX Should really reject non-string non-buffers + self._wbuf.extend(filter(None, map(str, list))) + if (self._wbufsize <= 1 or + self._get_wbuf_len() >= self._wbufsize): + self.flush() + + def _get_wbuf_len(self): + buf_len = 0 + for x in self._wbuf: + buf_len += len(x) + return buf_len + + def read(self, size=-1): + data = self._rbuf + if size < 0: + # Read until EOF + buffers = [] + if data: + buffers.append(data) + self._rbuf = "" + if self._rbufsize <= 1: + recv_size = self.default_bufsize + else: + recv_size = self._rbufsize + while True: + data = self._sock.recv(recv_size) + if not data: + break + buffers.append(data) + return "".join(buffers) + else: + # Read until size bytes or EOF seen, whichever comes first + buf_len = len(data) + if buf_len >= size: + self._rbuf = data[size:] + return data[:size] + buffers = [] + if data: + buffers.append(data) + self._rbuf = "" + while True: + left = size - buf_len + recv_size = max(self._rbufsize, left) + data = self._sock.recv(recv_size) + if not data: + break + buffers.append(data) + n = len(data) + if n >= left: + self._rbuf = data[left:] + buffers[-1] = data[:left] + break + buf_len += n + return "".join(buffers) + + def readline(self, size=-1): + data = self._rbuf + if size < 0: + # Read until \n or EOF, whichever comes first + if self._rbufsize <= 1: + # Speed up unbuffered case + assert data == "" + buffers = [] + recv = self._sock.recv + while data != "\n": + data = recv(1) + if not data: + break + buffers.append(data) + return "".join(buffers) + nl = data.find('\n') + if nl >= 0: + nl += 1 + self._rbuf = data[nl:] + return data[:nl] + buffers = [] + if data: + buffers.append(data) + self._rbuf = "" + while True: + data = self._sock.recv(self._rbufsize) + if not data: + break + buffers.append(data) + nl = data.find('\n') + if nl >= 0: + nl += 1 + self._rbuf = data[nl:] + buffers[-1] = data[:nl] + break + return "".join(buffers) + else: + # Read until size bytes or \n or EOF seen, whichever comes first + nl = data.find('\n', 0, size) + if nl >= 0: + nl += 1 + self._rbuf = data[nl:] + return data[:nl] + buf_len = len(data) + if buf_len >= size: + self._rbuf = data[size:] + return data[:size] + buffers = [] + if data: + buffers.append(data) + self._rbuf = "" + while True: + data = self._sock.recv(self._rbufsize) + if not data: + break + buffers.append(data) + left = size - buf_len + nl = data.find('\n', 0, left) + if nl >= 0: + nl += 1 + self._rbuf = data[nl:] + buffers[-1] = data[:nl] + break + n = len(data) + if n >= left: + self._rbuf = data[left:] + buffers[-1] = data[:left] + break + buf_len += n + return "".join(buffers) + + def readlines(self, sizehint=0): + total = 0 + list = [] + while True: + line = self.readline() + if not line: + break + list.append(line) + total += len(line) + if sizehint and total >= sizehint: + break + return list + + # Iterator protocols + + def __iter__(self): + return self + + def next(self): + line = self.readline() + if not line: + raise StopIteration + return line + + # Define the SSL support class ssl: Modified: trunk/jython/Lib/test/test_socket.py =================================================================== --- trunk/jython/Lib/test/test_socket.py 2007-11-10 02:36:44 UTC (rev 3662) +++ trunk/jython/Lib/test/test_socket.py 2007-11-10 02:43:29 UTC (rev 3663) @@ -583,6 +583,18 @@ time.sleep(0.5) self.fail("Sending on remotely closed socket should have raised exception") + def testDup(self): + msg = self.cli_conn.recv(len(MSG)) + self.assertEqual(msg, MSG) + + dup_conn = self.cli_conn.dup() + msg = dup_conn.recv(len('and ' + MSG)) + self.assertEqual(msg, 'and ' + MSG) + + def _testDup(self): + self.serv_conn.send(MSG) + self.serv_conn.send('and ' + MSG) + class BasicUDPTest(ThreadedUDPSocketTest): def __init__(self, methodName='runTest'): @@ -762,7 +774,7 @@ # TODO: Write some non-blocking UDP tests # -class FileObjectClassOpenCloseTests(SocketConnectedTest): +class TCPFileObjectClassOpenCloseTests(SocketConnectedTest): def testCloseFileDoesNotCloseSocket(self): # This test is necessary on java/jython @@ -790,6 +802,71 @@ except Exception, x: self.fail("Closing socket appears to have closed file wrapper: %s" % str(x)) +class UDPFileObjectClassOpenCloseTests(ThreadedUDPSocketTest): + + def testCloseFileDoesNotCloseSocket(self): + # This test is necessary on java/jython + msg = self.serv.recv(1024) + self.assertEqual(msg, MSG) + + def _testCloseFileDoesNotCloseSocket(self): + self.cli_file = self.cli.makefile('wb') + self.cli_file.close() + try: + self.cli.sendto(MSG, 0, (HOST, PORT)) + except Exception, x: + self.fail("Closing file wrapper appears to have closed underlying socket: %s" % str(x)) + + def testCloseSocketDoesNotCloseFile(self): + self.serv_file = self.serv.makefile('rb') + self.serv.close() + msg = self.serv_file.readline() + self.assertEqual(msg, MSG) + + def _testCloseSocketDoesNotCloseFile(self): + try: + self.cli.sendto(MSG, 0, (HOST, PORT)) + except Exception, x: + self.fail("Closing file wrapper appears to have closed underlying socket: %s" % str(x)) + +class FileAndDupOpenCloseTests(SocketConnectedTest): + + def testCloseDoesNotCloseOthers(self): + msg = self.cli_conn.recv(len(MSG)) + self.assertEqual(msg, MSG) + + msg = self.cli_conn.recv(len('and ' + MSG)) + self.assertEqual(msg, 'and ' + MSG) + + def _testCloseDoesNotCloseOthers(self): + self.dup_conn1 = self.serv_conn.dup() + self.dup_conn2 = self.serv_conn.dup() + self.cli_file = self.serv_conn.makefile('wb') + self.serv_conn.close() + self.dup_conn1.close() + + try: + self.serv_conn.send(MSG) + except socket.error, se: + self.failUnlessEqual(se[0], errno.EBADF) + else: + self.fail("Original socket did not close") + try: + self.dup_conn1.send(MSG) + except socket.error, se: + self.failUnlessEqual(se[0], errno.EBADF) + else: + self.fail("Duplicate socket 1 did not close") + + self.dup_conn2.send(MSG) + self.dup_conn2.close() + + try: + self.cli_file.write('and ' + MSG) + except Exception, x: + self.fail("Closing others appears to have closed the socket file: %s" % str(x)) + self.cli_file.close() + class FileObjectClassTestCase(SocketConnectedTest): bufsize = -1 # Use default buffer size @@ -1021,7 +1098,6 @@ else: self.fail("Binding to already bound host/port should have raised exception") - def testUnresolvedAddress(self): try: self.s.connect( ('non.existent.server', PORT) ) @@ -1050,6 +1126,26 @@ else: self.fail("Receive on unconnected socket raised exception") + def testClosedSocket(self): + self.s.close() + try: + self.s.send(MSG) + except socket.error, se: + self.failUnlessEqual(se[0], errno.EBADF) + + dup = self.s.dup() + try: + dup.send(MSG) + except socket.error, se: + self.failUnlessEqual(se[0], errno.EBADF) + + fp = self.s.makefile() + try: + fp.write(MSG) + fp.flush() + except socket.error, se: + self.failUnlessEqual(se[0], errno.EBADF) + class TestAddressParameters: def testBindNonTupleEndpointRaisesTypeError(self): @@ -1099,7 +1195,9 @@ UDPTimeoutTest, NonBlockingTCPTests, NonBlockingUDPTests, - FileObjectClassOpenCloseTests, + TCPFileObjectClassOpenCloseTests, + UDPFileObjectClassOpenCloseTests, + FileAndDupOpenCloseTests, FileObjectClassTestCase, UnbufferedFileObjectClassTestCase, LineBufferedFileObjectClassTestCase, This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <pj...@us...> - 2007-11-16 21:41:21
|
Revision: 3682 http://jython.svn.sourceforge.net/jython/?rev=3682&view=rev Author: pjenvey Date: 2007-11-16 13:41:19 -0800 (Fri, 16 Nov 2007) Log Message: ----------- Merged revisions 3649-3651,3653-3681 via svnmerge from https://jython.svn.sourceforge.net/svnroot/jython/branches/pyfile-nio rewrite of PyFile. most of its innards now live under the new org.python.core.io package, which is loosely based off of py3k's new io (PEP 3116): consits of 3 layers: o raw io (RawIOBase) - deals in nio Channels (mostly) and ByteBuffers o buffered io (BufferedIOBase) - buffers bytes to/from raw ios o text io (TextIOBase) - deals in Strings, via buffered ios features: o improved performance for larger files, especially for readline and 'r' (on CRLF platforms) and 'U' modes o full CPython-like buffering support (variable sized buffering, line buffering) o line buffered stdout, and support for jython -u to disable o thread safe PyFile o support for readinto, and isatty (only returns true for stdin/out/err) o fixes file.softspace o a modified 2.5.1 test_file now passes. test_dumbdbm also now passes and I don't know why also: o kill PythonInterpreter.setOut/Err(Writer) and the associated Writer backed PyFile support Modified Paths: -------------- trunk/jython/Lib/test/regrtest.py trunk/jython/Lib/test/test_file_newlines.py trunk/jython/src/org/python/core/Options.java trunk/jython/src/org/python/core/Py.java trunk/jython/src/org/python/core/PyArray.java trunk/jython/src/org/python/core/PyFile.java trunk/jython/src/org/python/core/PyString.java trunk/jython/src/org/python/core/PySystemState.java trunk/jython/src/org/python/core/StdoutWrapper.java trunk/jython/src/org/python/modules/cPickle.java trunk/jython/src/org/python/modules/imp.java trunk/jython/src/org/python/util/PythonInterpreter.java trunk/jython/src/org/python/util/jython.java trunk/jython/src/templates/file.expose Added Paths: ----------- trunk/jython/Lib/test/test_file.py trunk/jython/src/org/python/core/io/ trunk/jython/src/org/python/core/io/BinaryIOWrapper.java trunk/jython/src/org/python/core/io/BufferedIOBase.java trunk/jython/src/org/python/core/io/BufferedIOMixin.java trunk/jython/src/org/python/core/io/BufferedRandom.java trunk/jython/src/org/python/core/io/BufferedReader.java trunk/jython/src/org/python/core/io/BufferedWriter.java trunk/jython/src/org/python/core/io/DatagramSocketIO.java trunk/jython/src/org/python/core/io/FileIO.java trunk/jython/src/org/python/core/io/IOBase.java trunk/jython/src/org/python/core/io/LineBufferedRandom.java trunk/jython/src/org/python/core/io/LineBufferedWriter.java trunk/jython/src/org/python/core/io/RawIOBase.java trunk/jython/src/org/python/core/io/ServerSocketIO.java trunk/jython/src/org/python/core/io/SocketIO.java trunk/jython/src/org/python/core/io/SocketIOBase.java trunk/jython/src/org/python/core/io/StreamIO.java trunk/jython/src/org/python/core/io/TextIOBase.java trunk/jython/src/org/python/core/io/TextIOWrapper.java trunk/jython/src/org/python/core/io/UniversalIOWrapper.java Removed Paths: ------------- trunk/jython/src/org/python/core/io/BinaryIOWrapper.java trunk/jython/src/org/python/core/io/BufferedIOBase.java trunk/jython/src/org/python/core/io/BufferedIOMixin.java trunk/jython/src/org/python/core/io/BufferedRandom.java trunk/jython/src/org/python/core/io/BufferedReader.java trunk/jython/src/org/python/core/io/BufferedWriter.java trunk/jython/src/org/python/core/io/FileIO.java trunk/jython/src/org/python/core/io/IOBase.java trunk/jython/src/org/python/core/io/LineBufferedRandom.java trunk/jython/src/org/python/core/io/LineBufferedWriter.java trunk/jython/src/org/python/core/io/RawIOBase.java trunk/jython/src/org/python/core/io/SocketIO.java trunk/jython/src/org/python/core/io/StreamIO.java trunk/jython/src/org/python/core/io/TextIOBase.java trunk/jython/src/org/python/core/io/TextIOWrapper.java trunk/jython/src/org/python/core/io/UniversalIOWrapper.java Property Changed: ---------------- trunk/jython/ Property changes on: trunk/jython ___________________________________________________________________ Name: svnmerge-integrated - /branches/pyfile-nio:1-3648,3652 + /branches/pyfile-nio:1-3681 Modified: trunk/jython/Lib/test/regrtest.py =================================================================== --- trunk/jython/Lib/test/regrtest.py 2007-11-16 19:49:34 UTC (rev 3681) +++ trunk/jython/Lib/test/regrtest.py 2007-11-16 21:41:19 UTC (rev 3682) @@ -1035,9 +1035,7 @@ test_dis test_descr test_descrtut - test_dumbdbm test_eof - test_file test_frozen test_hexoct test_inspect Copied: trunk/jython/Lib/test/test_file.py (from rev 3651, branches/pyfile-nio/Lib/test/test_file.py) =================================================================== --- trunk/jython/Lib/test/test_file.py (rev 0) +++ trunk/jython/Lib/test/test_file.py 2007-11-16 21:41:19 UTC (rev 3682) @@ -0,0 +1,358 @@ +# From CPython 2.5.1 +import sys +import os +import unittest +from array import array +from weakref import proxy + +from test.test_support import TESTFN, findfile, run_unittest +from UserList import UserList + +class AutoFileTests(unittest.TestCase): + # file tests for which a test file is automatically set up + + def setUp(self): + self.f = open(TESTFN, 'wb') + + def tearDown(self): + if self.f: + self.f.close() + os.remove(TESTFN) + + # XXX: assumes CPython style garbage collection + def _testWeakRefs(self): + # verify weak references + p = proxy(self.f) + p.write('teststring') + self.assertEquals(self.f.tell(), p.tell()) + self.f.close() + self.f = None + self.assertRaises(ReferenceError, getattr, p, 'tell') + + def testAttributes(self): + # verify expected attributes exist + f = self.f + softspace = f.softspace + f.name # merely shouldn't blow up + f.mode # ditto + f.closed # ditto + + # verify softspace is writable + f.softspace = softspace # merely shouldn't blow up + + # verify the others aren't + for attr in 'name', 'mode', 'closed': + self.assertRaises((AttributeError, TypeError), setattr, f, attr, 'oops') + + def testReadinto(self): + # verify readinto + self.f.write('12') + self.f.close() + a = array('c', 'x'*10) + self.f = open(TESTFN, 'rb') + n = self.f.readinto(a) + self.assertEquals('12', a.tostring()[:n]) + + def testWritelinesUserList(self): + # verify writelines with instance sequence + l = UserList(['1', '2']) + self.f.writelines(l) + self.f.close() + self.f = open(TESTFN, 'rb') + buf = self.f.read() + self.assertEquals(buf, '12') + + def testWritelinesIntegers(self): + # verify writelines with integers + self.assertRaises(TypeError, self.f.writelines, [1, 2, 3]) + + def testWritelinesIntegersUserList(self): + # verify writelines with integers in UserList + l = UserList([1,2,3]) + self.assertRaises(TypeError, self.f.writelines, l) + + def testWritelinesNonString(self): + # verify writelines with non-string object + class NonString: + pass + + self.assertRaises(TypeError, self.f.writelines, + [NonString(), NonString()]) + + def testRepr(self): + # verify repr works + self.assert_(repr(self.f).startswith("<open file '" + TESTFN)) + + def testErrors(self): + f = self.f + self.assertEquals(f.name, TESTFN) + # XXX: Jython doesn't support isatty + #self.assert_(not f.isatty()) + self.assert_(not f.closed) + + self.assertRaises(TypeError, f.readinto, "") + f.close() + self.assert_(f.closed) + + def testMethods(self): + # XXX: Jython file methods require valid arguments: closed file + # checks are done before parsing the arguments in CPython + #methods = ['next', 'read', 'readinto', + # 'readline', 'readlines', 'seek', 'tell', 'truncate', + # 'write', 'xreadlines', '__iter__'] + noarg = object() + # XXX: Jython doesn't support fileno or isatty + #methods = dict(fileno=noarg, flush=noarg, isatty=noarg, next=noarg, + methods = dict(flush=noarg, next=noarg, + read=-1, readinto=array('c', 'x'), readline=-1, + readlines=noarg, seek=0, tell=noarg, truncate=0, + write='x', xreadlines=noarg, __iter__=noarg) + if sys.platform.startswith('atheos'): + methods.remove('truncate') + + # __exit__ should close the file + # XXX: __exit__ is 2.5 specific + #self.f.__exit__(None, None, None) + self.f.close() + self.assert_(self.f.closed) + + for methodname, arg in methods.iteritems(): + method = getattr(self.f, methodname) + # should raise on closed file + if arg is noarg: + self.assertRaises(ValueError, method) + else: + self.assertRaises(ValueError, method, arg) + self.assertRaises(ValueError, self.f.writelines, []) + + # XXX: __exit__ is 2.5 specific + return + # file is closed, __exit__ shouldn't do anything + self.assertEquals(self.f.__exit__(None, None, None), None) + # it must also return None if an exception was given + try: + 1/0 + except: + self.assertEquals(self.f.__exit__(*sys.exc_info()), None) + + +class OtherFileTests(unittest.TestCase): + + def testModeStrings(self): + # check invalid mode strings + for mode in ("", "aU", "wU+"): + try: + f = open(TESTFN, mode) + except ValueError: + pass + else: + f.close() + self.fail('%r is an invalid file mode' % mode) + + # XXX: Jython's stdin can't seek, it's not backed by a + # RandomAccessFile + def _testStdin(self): + # This causes the interpreter to exit on OSF1 v5.1. + if sys.platform != 'osf1V5': + self.assertRaises(IOError, sys.stdin.seek, -1) + else: + print >>sys.__stdout__, ( + ' Skipping sys.stdin.seek(-1), it may crash the interpreter.' + ' Test manually.') + self.assertRaises(IOError, sys.stdin.truncate) + + def testUnicodeOpen(self): + # verify repr works for unicode too + f = open(unicode(TESTFN), "w") + self.assert_(repr(f).startswith("<open file u'" + TESTFN)) + f.close() + os.unlink(TESTFN) + + def testBadModeArgument(self): + # verify that we get a sensible error message for bad mode argument + bad_mode = "qwerty" + try: + f = open(TESTFN, bad_mode) + except ValueError, msg: + if msg[0] != 0: + s = str(msg) + if s.find(TESTFN) != -1 or s.find(bad_mode) == -1: + self.fail("bad error message for invalid mode: %s" % s) + # if msg[0] == 0, we're probably on Windows where there may be + # no obvious way to discover why open() failed. + else: + f.close() + self.fail("no error for invalid mode: %s" % bad_mode) + + def testSetBufferSize(self): + # make sure that explicitly setting the buffer size doesn't cause + # misbehaviour especially with repeated close() calls + for s in (-1, 0, 1, 512): + try: + f = open(TESTFN, 'w', s) + f.write(str(s)) + f.close() + f.close() + f = open(TESTFN, 'r', s) + d = int(f.read()) + f.close() + f.close() + except IOError, msg: + self.fail('error setting buffer size %d: %s' % (s, str(msg))) + self.assertEquals(d, s) + + def testTruncateOnWindows(self): + os.unlink(TESTFN) + + def bug801631(): + # SF bug <http://www.python.org/sf/801631> + # "file.truncate fault on windows" + f = open(TESTFN, 'wb') + f.write('12345678901') # 11 bytes + f.close() + + f = open(TESTFN,'rb+') + data = f.read(5) + if data != '12345': + self.fail("Read on file opened for update failed %r" % data) + if f.tell() != 5: + self.fail("File pos after read wrong %d" % f.tell()) + + f.truncate() + if f.tell() != 5: + self.fail("File pos after ftruncate wrong %d" % f.tell()) + + f.close() + size = os.path.getsize(TESTFN) + if size != 5: + self.fail("File size after ftruncate wrong %d" % size) + + try: + bug801631() + finally: + os.unlink(TESTFN) + + # XXX: Jython allows mixing reads with iteration + def _testIteration(self): + # Test the complex interaction when mixing file-iteration and the + # various read* methods. Ostensibly, the mixture could just be tested + # to work when it should work according to the Python language, + # instead of fail when it should fail according to the current CPython + # implementation. People don't always program Python the way they + # should, though, and the implemenation might change in subtle ways, + # so we explicitly test for errors, too; the test will just have to + # be updated when the implementation changes. + dataoffset = 16384 + filler = "ham\n" + assert not dataoffset % len(filler), \ + "dataoffset must be multiple of len(filler)" + nchunks = dataoffset // len(filler) + testlines = [ + "spam, spam and eggs\n", + "eggs, spam, ham and spam\n", + "saussages, spam, spam and eggs\n", + "spam, ham, spam and eggs\n", + "spam, spam, spam, spam, spam, ham, spam\n", + "wonderful spaaaaaam.\n" + ] + methods = [("readline", ()), ("read", ()), ("readlines", ()), + ("readinto", (array("c", " "*100),))] + + try: + # Prepare the testfile + bag = open(TESTFN, "w") + bag.write(filler * nchunks) + bag.writelines(testlines) + bag.close() + # Test for appropriate errors mixing read* and iteration + for methodname, args in methods: + f = open(TESTFN) + if f.next() != filler: + self.fail, "Broken testfile" + meth = getattr(f, methodname) + try: + meth(*args) + except ValueError: + pass + else: + self.fail("%s%r after next() didn't raise ValueError" % + (methodname, args)) + f.close() + + # Test to see if harmless (by accident) mixing of read* and + # iteration still works. This depends on the size of the internal + # iteration buffer (currently 8192,) but we can test it in a + # flexible manner. Each line in the bag o' ham is 4 bytes + # ("h", "a", "m", "\n"), so 4096 lines of that should get us + # exactly on the buffer boundary for any power-of-2 buffersize + # between 4 and 16384 (inclusive). + f = open(TESTFN) + for i in range(nchunks): + f.next() + testline = testlines.pop(0) + try: + line = f.readline() + except ValueError: + self.fail("readline() after next() with supposedly empty " + "iteration-buffer failed anyway") + if line != testline: + self.fail("readline() after next() with empty buffer " + "failed. Got %r, expected %r" % (line, testline)) + testline = testlines.pop(0) + buf = array("c", "\x00" * len(testline)) + try: + f.readinto(buf) + except ValueError: + self.fail("readinto() after next() with supposedly empty " + "iteration-buffer failed anyway") + line = buf.tostring() + if line != testline: + self.fail("readinto() after next() with empty buffer " + "failed. Got %r, expected %r" % (line, testline)) + + testline = testlines.pop(0) + try: + line = f.read(len(testline)) + except ValueError: + self.fail("read() after next() with supposedly empty " + "iteration-buffer failed anyway") + if line != testline: + self.fail("read() after next() with empty buffer " + "failed. Got %r, expected %r" % (line, testline)) + try: + lines = f.readlines() + except ValueError: + self.fail("readlines() after next() with supposedly empty " + "iteration-buffer failed anyway") + if lines != testlines: + self.fail("readlines() after next() with empty buffer " + "failed. Got %r, expected %r" % (line, testline)) + # Reading after iteration hit EOF shouldn't hurt either + f = open(TESTFN) + try: + for line in f: + pass + try: + f.readline() + f.readinto(buf) + f.read() + f.readlines() + except ValueError: + self.fail("read* failed after next() consumed file") + finally: + f.close() + finally: + os.unlink(TESTFN) + + +def test_main(): + # Historically, these tests have been sloppy about removing TESTFN. + # So get rid of it no matter what. + try: + run_unittest(AutoFileTests, OtherFileTests) + finally: + if os.path.exists(TESTFN): + os.unlink(TESTFN) + +if __name__ == '__main__': + test_main() Modified: trunk/jython/Lib/test/test_file_newlines.py =================================================================== --- trunk/jython/Lib/test/test_file_newlines.py 2007-11-16 19:49:34 UTC (rev 3681) +++ trunk/jython/Lib/test/test_file_newlines.py 2007-11-16 21:41:19 UTC (rev 3682) @@ -3,6 +3,7 @@ Made for Jython. """ import os +import sys import tempfile import test.test_support as test_support import unittest @@ -15,6 +16,12 @@ CRLF_TEST = 'CR\rLF\nCRLF\r\nEOF' +if sys.platform.startswith('java'): + from org.python.core.io import TextIOBase + READAHEAD_SIZE = TextIOBase.CHUNK_SIZE +else: + READAHEAD_SIZE = 300 + class BaseTestCase(unittest.TestCase): data = CRLF_TEST @@ -23,18 +30,20 @@ def setUp(self): self.filename = tempfile.mktemp() - fp = open(self.filename, self.write_mode) - fp.write(self.data) - fp.close() + self.write_fp = open(self.filename, self.write_mode) + self.write_fp.write(self.data) + self.write_fp.flush() self.fp = open(self.filename, self.mode) def tearDown(self): + if self.write_fp: + self.write_fp.close() if self.fp: self.fp.close() os.remove(self.filename) -class BinaryNewlinesTestCase(BaseTestCase): +class ReadBinaryNewlinesTestCase(BaseTestCase): mode = 'rb' @@ -44,62 +53,212 @@ self.fp.seek(0) read(self.fp, CRLF_TEST, len(CRLF_TEST)) + self.fp.seek(0) + read(self.fp, 'CR\r', 3) + read(self.fp, 'LF\n', 3) + read(self.fp, 'CRLF\r\n', 6) + read(self.fp, 'EOF', 3) + def test_binary_readline(self): readline(self.fp, 'CR\rLF\n') readline(self.fp, 'CRLF\r\n') readline(self.fp, 'EOF') + self.fp.seek(0) + readline(self.fp, 'CR\rLF\n', 6) + readline(self.fp, 'CRLF\r\n', 6) + readline(self.fp, 'EOF', 3) -class ReadTextNewlinesTestCase(BaseTestCase): - def test_text_read(self): - if LF: - read(self.fp, 'CR\rLF\nCRLF\r\nEOF') - elif CRLF: +if LF: + class ReadTextNewlinesTestCase(ReadBinaryNewlinesTestCase): + + mode = 'r' + +else: + class ReadTextNewlinesTestCase(BaseTestCase): + + def test_text_read(self): read(self.fp, 'CR\rLF\nCRLF\nEOF') - self.fp.seek(0) - read(self.fp, 'CR\r', 3) - read(self.fp, 'LF\n', 3) - if LF: - read(self.fp, 'CRLF\r\n', 6) - elif CRLF: + self.fp.seek(0) + read(self.fp, 'CR\rLF\nCRLF\nEOF', len('CR\rLF\nCRLF\nEOF')) + + self.fp.seek(0) + read(self.fp, 'CR\r', 3) + read(self.fp, 'LF\n', 3) read(self.fp, 'CRLF\n', 5) - read(self.fp, 'EOF', 3) + read(self.fp, 'EOF', 3) - def _test_text_readline(self): - readline(self.fp, 'CR\rLF\n') - if LF: - readline(self.fp, 'CRLF\r\n') - elif CRLF: + def test_text_readline(self): + readline(self.fp, 'CR\rLF\n') readline(self.fp, 'CRLF\n') - readline(self.fp, 'EOF') + readline(self.fp, 'EOF') - self.fp.seek(0) - readline(self.fp, 'CR\rLF\n') - if LF: - readline(self.fp, 'CRLF\r', 5) - readline(self.fp, '\n') - elif CRLF: + self.fp.seek(0) + readline(self.fp, 'CR\rLF\n', 6) readline(self.fp, 'CRLF\n', 5) - readline(self.fp, 'EOF') + readline(self.fp, 'EOF', 3) -class ReadTextBoundaryTestCase(BaseTestCase): +class ReadTextBasicBoundaryTestCase(BaseTestCase): data = 'CR\r' + read_data = 'CR\r' - def test_read_boundary(self): - read(self.fp, 'CR\r') + def test_read_basic_boundary(self): + read(self.fp, self.read_data) self.fp.seek(0) - read(self.fp, 'CR\r', 3) + read(self.fp, self.read_data, 3) + def test_readline_basic_boundary(self): + readline(self.fp, self.read_data) + self.fp.seek(0) + readline(self.fp, self.read_data, 3) + + +class ReadUniversalBasicBoundaryTestCase(ReadTextBasicBoundaryTestCase): + + mode = 'U' + read_data = 'CR\n' + + +class BinaryReadaheadBoundaryTestCase(BaseTestCase): + + mode = 'rb' + data = 'foo\n' + ('x' * READAHEAD_SIZE) + + def test_read_boundary(self): + readline(self.fp, 'foo\n') + read(self.fp, 'x' * READAHEAD_SIZE, READAHEAD_SIZE) + def test_readline_boundary(self): - readline(self.fp, 'CR\r') + readline(self.fp, 'foo\n') + readline(self.fp, 'x' * READAHEAD_SIZE, READAHEAD_SIZE) + + +class TextReadaheadBoundaryTestCase(BinaryReadaheadBoundaryTestCase): + + mode = 'r' + + +class UniversalReadaheadBoundaryTestCase(BinaryReadaheadBoundaryTestCase): + + mode = 'U' + + +class TextReadaheadBoundary2TestCase(BaseTestCase): + """For CRLF platforms only""" + + data = ('x' * (READAHEAD_SIZE + 1)) + '\r\n' + + def test_read_boundary2(self): + read(self.fp, 'x' * (READAHEAD_SIZE + 1), READAHEAD_SIZE + 1) + read(self.fp, '\n') + + +class UniversalReadaheadBoundary2TestCase(TextReadaheadBoundary2TestCase): + + mode = 'U' + + +class TextReadaheadBoundary3TestCase(BaseTestCase): + """For CRLF platforms only""" + + mode = 'r' + data = ('x' * (READAHEAD_SIZE - 1)) + '\r\n' + + def test_read_boundary3(self): + size = READAHEAD_SIZE - 1 + read(self.fp, 'x' * size, size) + read(self.fp, '\n') self.fp.seek(0) - readline(self.fp, 'CR\r', 3) + read(self.fp, ('x' * size) + '\n', READAHEAD_SIZE) + def test_readline_boundary3(self): + size = READAHEAD_SIZE - 1 + readline(self.fp, 'x' * size, size) + readline(self.fp, '\n') + def test_read_boundary3_with_extra(self): + self.write_fp.seek(0, 2) + self.write_fp.write('foo') + self.write_fp.flush() + self.write_fp.seek(0) + + size = READAHEAD_SIZE - 1 + read(self.fp, ('x' * size) + '\nfoo', READAHEAD_SIZE + 3) + + +class UniversalReadaheadBoundary3TestCase(TextReadaheadBoundary3TestCase): + + mode = 'U' + + +class TextReadaheadBoundary4TestCase(BaseTestCase): + """For CRLF platforms only""" + + mode = 'r' + data = ('x' * (READAHEAD_SIZE - 2)) + '\n\r' + + def test_read_boundary4(self): + readline(self.fp, 'x' * (READAHEAD_SIZE - 2) + '\n') + + self.write_fp.write('\n') + self.write_fp.flush() + + read(self.fp, '\n') + + def test_readline_boundary4(self): + readline(self.fp, 'x' * (READAHEAD_SIZE - 2) + '\n') + + self.write_fp.write('\n') + self.write_fp.flush() + + readline(self.fp, '\n') + + +class UniversalReadaheadBoundary4TestCase(TextReadaheadBoundary4TestCase): + + mode = 'U' + data = ('x' * (READAHEAD_SIZE - 2)) + '\n\r' + + +class TextReadaheadBoundary5TestCase(BaseTestCase): + """For CRLF platforms only""" + + mode = 'r' + data = 'foobar\n' + ('x' * (READAHEAD_SIZE + 1)) + + def test_boundary5(self): + readline(self.fp, 'foobar\n') + read(self.fp, 'x' * (READAHEAD_SIZE + 1), READAHEAD_SIZE + 1) + + +class UniversalReadaheadBoundary5TestCase(TextReadaheadBoundary5TestCase): + + mode = 'U' + + +class TextCRAtReadheadBoundaryTestCase(BaseTestCase): + """For CRLF platforms only""" + + data = ('x' * (READAHEAD_SIZE - 1)) + '\rfoo' + read_data = data + + def test_readline_cr_at_boundary(self): + readline(self.fp, self.read_data, len(self.read_data)) + self.fp.seek(0) + readline(self.fp, self.read_data) + + +class TextCRAtReadheadBoundary2TestCase(TextCRAtReadheadBoundaryTestCase): + """For CRLF platforms only""" + + data = ('x' * (READAHEAD_SIZE - 1)) + '\r' + ('x' * 300) + read_data = data + + class WriteTextNewlinesTestCase(BaseTestCase): write_mode = 'w' @@ -161,8 +320,8 @@ else: raise AssertionError("file mode 'wU' did not raise a " "ValueError") - + def read(fp, data, size=-1): line = fp.read(size) assert line == data, 'read: %r expected: %r' % (line, data) @@ -174,12 +333,28 @@ def test_main(): - test_support.run_unittest(BinaryNewlinesTestCase, - ReadTextNewlinesTestCase, - ReadTextBoundaryTestCase, - WriteTextNewlinesTestCase, - ReadUniversalNewlinesTestCase, - WriteUniversalNewlinesTestCase) + tests = [ReadBinaryNewlinesTestCase, + ReadTextNewlinesTestCase, + ReadTextBasicBoundaryTestCase, + ReadUniversalBasicBoundaryTestCase, + BinaryReadaheadBoundaryTestCase, + TextReadaheadBoundaryTestCase, + UniversalReadaheadBoundaryTestCase, + UniversalReadaheadBoundary2TestCase, + UniversalReadaheadBoundary3TestCase, + UniversalReadaheadBoundary4TestCase, + UniversalReadaheadBoundary5TestCase, + WriteTextNewlinesTestCase, + ReadUniversalNewlinesTestCase, + WriteUniversalNewlinesTestCase] + if CRLF: + tests.extend([TextReadaheadBoundary2TestCase, + TextReadaheadBoundary3TestCase, + TextReadaheadBoundary4TestCase, + TextReadaheadBoundary5TestCase, + TextCRAtReadheadBoundaryTestCase, + TextCRAtReadheadBoundary2TestCase]) + test_support.run_unittest(*tests) if __name__ == '__main__': test_main() Modified: trunk/jython/src/org/python/core/Options.java =================================================================== --- trunk/jython/src/org/python/core/Options.java 2007-11-16 19:49:34 UTC (rev 3681) +++ trunk/jython/src/org/python/core/Options.java 2007-11-16 21:41:19 UTC (rev 3682) @@ -71,6 +71,10 @@ */ public static boolean Qnew = false; + /** Force stdin, stdout and stderr to be unbuffered, and opened in + * binary mode */ + public static boolean unbuffered = false; + /** * Enable division warning. The value maps to the registry values of * <ul> Modified: trunk/jython/src/org/python/core/Py.java =================================================================== --- trunk/jython/src/org/python/core/Py.java 2007-11-16 19:49:34 UTC (rev 3681) +++ trunk/jython/src/org/python/core/Py.java 2007-11-16 21:41:19 UTC (rev 3682) @@ -11,7 +11,6 @@ import java.io.PrintStream; import java.io.Serializable; import java.io.StreamCorruptedException; -import java.io.Writer; import java.lang.reflect.InvocationTargetException; import org.python.compiler.Module; @@ -151,6 +150,12 @@ return new PyException(Py.IOError, message); } + public static PyException IOError(int errno, String message) { + PyTuple args = new PyTuple(new PyObject[] {new PyInteger(errno), + new PyString(message)}); + return new PyException(Py.IOError, args); + } + public static PyObject KeyError; public static PyException KeyError(String message) { return new PyException(Py.KeyError, message); @@ -1304,7 +1309,7 @@ contents = o.toString(); else if (o instanceof PyFile) { PyFile fp = (PyFile)o; - if (fp.closed) + if (fp.getClosed()) return; contents = fp.read().toString(); } else @@ -2047,16 +2052,9 @@ this.file = file; if (file instanceof PyJavaInstance) { - Object tmp = file.__tojava__(OutputStream.class); - if ((tmp != Py.NoConversion) && (tmp != null)) { - OutputStream os = (OutputStream)tmp; - this.file = new PyFile(os, "<java OutputStream>"); - } else { - tmp = file.__tojava__(Writer.class); - if ((tmp != Py.NoConversion) && (tmp != null)) { - Writer w = (Writer)tmp; - this.file = new PyFile(w, "<java Writer>"); - } + Object tojava = file.__tojava__(OutputStream.class); + if (tojava != null && tojava != Py.NoConversion) { + this.file = new PyFile((OutputStream)tojava, "<java OutputStream>"); } } } Modified: trunk/jython/src/org/python/core/PyArray.java =================================================================== --- trunk/jython/src/org/python/core/PyArray.java 2007-11-16 19:49:34 UTC (rev 3681) +++ trunk/jython/src/org/python/core/PyArray.java 2007-11-16 21:41:19 UTC (rev 3682) @@ -1581,7 +1581,7 @@ * @param value * value to set the element to */ - protected void set(int i, PyObject value) { + public void set(int i, PyObject value) { // check for overflow of the integral types if(type == Byte.TYPE) { long val; Modified: trunk/jython/src/org/python/core/PyFile.java =================================================================== --- trunk/jython/src/org/python/core/PyFile.java 2007-11-16 19:49:34 UTC (rev 3681) +++ trunk/jython/src/org/python/core/PyFile.java 2007-11-16 21:41:19 UTC (rev 3682) @@ -1,26 +1,25 @@ // Copyright (c) Corporation for National Research Initiatives package org.python.core; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; -import java.io.PushbackInputStream; import java.io.RandomAccessFile; -import java.io.Writer; - -import java.util.EnumSet; -import java.util.Iterator; import java.util.LinkedList; -// To do: -// - readinto(array) -// - modes w, a should disallow reading -// - what to do about buffer size? -// - isatty() -// - fileno() (defined, but always raises an exception, for urllib) +import org.python.core.io.BinaryIOWrapper; +import org.python.core.io.BufferedIOBase; +import org.python.core.io.BufferedRandom; +import org.python.core.io.BufferedReader; +import org.python.core.io.BufferedWriter; +import org.python.core.io.FileIO; +import org.python.core.io.IOBase; +import org.python.core.io.LineBufferedRandom; +import org.python.core.io.LineBufferedWriter; +import org.python.core.io.RawIOBase; +import org.python.core.io.StreamIO; +import org.python.core.io.TextIOBase; +import org.python.core.io.TextIOWrapper; +import org.python.core.io.UniversalIOWrapper; /** * A python file wrapper around a java stream, reader/writer or file. @@ -39,6 +38,7 @@ dict.__setitem__("name",new PyGetSetDescr("name",PyFile.class,"getName",null,null)); dict.__setitem__("closed",new PyGetSetDescr("closed",PyFile.class,"getClosed",null,null)); dict.__setitem__("newlines",new PyGetSetDescr("newlines",PyFile.class,"getNewlines",null,null)); + dict.__setitem__("softspace",new PyGetSetDescr("softspace",PyFile.class,"getSoftspace","setSoftspace","delSoftspace")); class exposed___cmp__ extends PyBuiltinMethodNarrow { exposed___cmp__(PyObject self,PyBuiltinFunction.Info info) { @@ -205,6 +205,22 @@ } dict.__setitem__("read",new PyMethodDescr("read",PyFile.class,0,1,new exposed_read(null,null))); + class exposed_readinto extends PyBuiltinMethodNarrow { + + exposed_readinto(PyObject self,PyBuiltinFunction.Info info) { + super(self,info); + } + + public PyBuiltinFunction bind(PyObject self) { + return new exposed_readinto(self,info); + } + + public PyObject __call__(PyObject arg0) { + return Py.newInteger(((PyFile)self).file_readinto(arg0)); + } + + } + dict.__setitem__("readinto",new PyMethodDescr("readinto",PyFile.class,1,1,new exposed_readinto(null,null))); class exposed_readline extends PyBuiltinMethodNarrow { exposed_readline(PyObject self,PyBuiltinFunction.Info info) { @@ -395,8 +411,8 @@ } public PyObject __call__(PyObject arg0) { - ((PyFile)self).file_write(arg0); - return Py.None; + ((PyFile)self).file_write(arg0); + return Py.None; } } @@ -491,74 +507,77 @@ } //~ END GENERATED REGION -- DO NOT EDIT SEE gexpose.py - public String name; + /** The filename */ + private PyObject name; + + /** The mode string */ public String mode; - public boolean softspace; - public boolean closed; - private FileWrapper file; + /** Indicator dictating whether a space should be written to this + * file on the next print statement (not currently implemented in + * print ) */ + public boolean softspace = false; - private boolean universal = false; + /** Whether this file is opened for reading */ + private boolean reading = false; + + /** Whether this file is opened for writing */ + private boolean writing = false; + + /** Whether this file is opened in appending mode */ + private boolean appending = false; + + /** Whether this file is opened for updating */ + private boolean updating = false; + + /** Whether this file is opened in binary mode */ private boolean binary = false; + /** Whether this file is opened in universal newlines mode */ + private boolean universal = false; + + /** The underlying IO object */ + private TextIOBase file; + + /** The file's closer object; ensures the file is closed at + * shutdown */ private Closer closer; + + /** All PyFiles' closers */ private static LinkedList closers = new LinkedList(); + static { - try { - Runtime.getRuntime().addShutdownHook(new PyFileCloser()); - } catch(SecurityException e) { - Py.writeDebug("PyFile", "Can't register file closer hook"); - } + initCloser(); } - private static InputStream _pb(InputStream s, String mode) - { - if (mode.contains("b")) { - if (s instanceof PushbackInputStream) { - return s; - } - return new PushbackInputStream(s); - } - return s; + public PyFile() { } - final void file_init(PyObject[] args,String[] kwds) { - - ArgParser ap = new ArgParser("file", args, kwds, - new String[] { "name", "mode", "bufsize" }, 1); - String nameArg = ap.getString(0, null); - String modeArg = ap.getString(1, "r"); - int buffArg = ap.getInt(2, 0); - file_init(_setup(nameArg, modeArg, buffArg), nameArg, modeArg); + public PyFile(PyType subType) { + super(subType); } - public PyFile() { - // xxx: this constructor should only be used in conjunction with file_init + public PyFile(RawIOBase raw, String name, String mode, int bufsize) { + parseMode(mode); + file_init(raw, name, mode, bufsize); } - public PyFile(PyType subType) { - super(subType); + public PyFile(InputStream istream, OutputStream ostream, String name, + String mode, int bufsize, boolean closefd) { + parseMode(mode); + file_init(new StreamIO(istream, ostream, closefd), name, mode, bufsize); } - private void file_init(FileWrapper file, String name, String mode) { - file.setMode(mode); - this.name = name; - this.mode = mode; - this.softspace = false; - this.closed = false; - if (universal) { - this.file = new UniversalWrapper(file); - } else if (!binary) { - this.file = new TextWrapper(file); - } else { - this.file = file; - } + public PyFile(InputStream istream, OutputStream ostream, String name, + String mode, int bufsize) + { + this(istream, ostream, name, mode, -1, true); } public PyFile(InputStream istream, OutputStream ostream, String name, String mode) { - file_init(new IOStreamWrapper(_pb(istream, mode), ostream), name, mode); + this(istream, ostream, name, mode, -1); } public PyFile(InputStream istream, OutputStream ostream, String name) @@ -570,8 +589,18 @@ this(istream, ostream, "<???>", "r+"); } + public PyFile(InputStream istream, String name, String mode, int bufsize, + boolean closefd) { + parseMode(mode); + file_init(new StreamIO(istream, closefd), name, mode, bufsize); + } + + public PyFile(InputStream istream, String name, String mode, int bufsize) { + this(istream, name, mode, -1, true); + } + public PyFile(InputStream istream, String name, String mode) { - file_init(new InputStreamWrapper(_pb(istream, mode)), name, mode); + this(istream, name, mode, -1); } public PyFile(InputStream istream, String name) { @@ -582,8 +611,18 @@ this(istream, "<???>", "r"); } + public PyFile(OutputStream ostream, String name, String mode, int bufsize, + boolean closefd) { + parseMode(mode); + file_init(new StreamIO(ostream, closefd), name, mode, bufsize); + } + + public PyFile(OutputStream ostream, String name, String mode, int bufsize) { + this(ostream, name, mode, -1, true); + } + public PyFile(OutputStream ostream, String name, String mode) { - file_init(new OutputStreamWrapper(ostream), name, mode); + this(ostream, name, mode, -1); } public PyFile(OutputStream ostream, String name) { @@ -594,20 +633,12 @@ this(ostream, "<???>", "w"); } - public PyFile(Writer ostream, String name, String mode) { - file_init(new WriterWrapper(ostream), name, mode); + public PyFile(RandomAccessFile file, String name, String mode, int bufsize) { + file_init(new FileIO(file.getChannel(), parseMode(mode)), name, mode, bufsize); } - public PyFile(Writer ostream, String name) { - this(ostream, name, "w"); - } - - public PyFile(Writer ostream) { - this(ostream, "<???>", "w"); - } - public PyFile(RandomAccessFile file, String name, String mode) { - file_init(new RFileWrapper(file), name, mode); + this(file, name, mode, -1); } public PyFile(RandomAccessFile file, String name) { @@ -619,67 +650,82 @@ } public PyFile(String name, String mode, int bufsize) { - file_init(_setup(name, mode, bufsize), name, mode); + file_init(new FileIO(name, parseMode(mode)), name, mode, bufsize); } - public void __setattr__(String name, PyObject value) { - // softspace is the only writeable file object attribute - if (name == "softspace") - softspace = value.__nonzero__(); - else if (name == "mode" || name == "closed" || name == "name") - throw Py.TypeError("readonly attribute: " + name); - else - throw Py.AttributeError(name); + final void file_init(PyObject[] args,String[] kwds) { + ArgParser ap = new ArgParser("file", args, kwds, + new String[] { "name", "mode", "bufsize" }, 1); + PyObject name = ap.getPyObject(0); + if (!(name instanceof PyString)) { + throw Py.TypeError("coercing to Unicode: need string, '" + + name.getType().getFullName() + "'type found"); + } + String mode = ap.getString(1, "r"); + int bufsize = ap.getInt(2, -1); + file_init(new FileIO(name.toString(), parseMode(mode)), name, mode, bufsize); } - public Object __tojava__(Class cls) { - Object o = null; - try { - o = file.__tojava__(cls); - } catch (IOException exc) { } - if (o == null) - o = super.__tojava__(cls); - return o; + private void file_init(RawIOBase raw, String name, String mode, int bufsize) { + file_init(raw, new PyString(name), mode, bufsize); } - private FileWrapper _setup(String name, String mode, int bufsize) { - String jmode = sanitizeMode(mode); - char c1 = mode.charAt(0); - try { - File f = new File(name); - if (c1 == 'r') { - if (!f.exists()) { - throw Py.IOError("No such file or directory: '" + name + "'"); - } - } - if (c1 == 'w') { - // Hack to truncate the file without deleting it: - // create a FileOutputStream for it and close it again. - FileOutputStream fo = new FileOutputStream(f); - fo.close(); - fo = null; - } - // What about bufsize? - RandomAccessFile rfile = new RandomAccessFile(f, jmode); - RFileWrapper iofile = new RFileWrapper(rfile); - if (c1 == 'a') - iofile.seek(0, 2); - return iofile; - } catch (IOException e) { - throw Py.IOError(e); + private void file_init(RawIOBase raw, PyObject name, String mode, int bufsize) { + this.name = name; + this.mode = mode; + + BufferedIOBase buffer = createBuffer(raw, bufsize); + if (universal) { + this.file = new UniversalIOWrapper(buffer); + } else if (!binary) { + this.file = new TextIOWrapper(buffer); + } else { + this.file = new BinaryIOWrapper(buffer); } } /** + * Wrap the given RawIOBase with a BufferedIOBase according to the + * mode and given bufsize. + * + * @param raw a RawIOBase value + * @param bufsize an int size of the buffer + * @return a BufferedIOBase wrapper + */ + private BufferedIOBase createBuffer(RawIOBase raw, int bufsize) { + if (bufsize < 0) { + bufsize = IOBase.DEFAULT_BUFFER_SIZE; + } + boolean lineBuffered = bufsize == 1; + BufferedIOBase buffer; + if (updating) { + buffer = lineBuffered ? + new LineBufferedRandom(raw) : + new BufferedRandom(raw, bufsize); + } else if (writing || appending) { + buffer = lineBuffered ? + new LineBufferedWriter(raw) : + new BufferedWriter(raw, bufsize); + } else if (reading) { + // Line buffering is for output only + buffer = new BufferedReader(raw, lineBuffered ? 0 : bufsize); + } else { + // Should never happen + throw Py.ValueError("unknown mode: '" + mode + "'"); + } + return buffer; + } + + /** * Parse and validate the python file mode, returning a cleaned - * file mode suitable for RandomAccessFile + * file mode suitable for FileIO. * * @param mode a python file mode String * @return a RandomAccessFile mode String */ - private String sanitizeMode(String mode) { + private String parseMode(String mode) { if (mode.length() == 0) { - throw Py.IOError("invalid mode: "); + throw Py.ValueError("empty mode string"); } String origMode = mode; @@ -699,37 +745,18 @@ } binary = mode.contains("b"); + reading = mode.contains("r"); + writing = mode.contains("w"); + appending = mode.contains("a"); + updating = mode.contains("+"); - int maxSearch = mode.length() < 3 ? mode.length() : 3; - if ("wa".indexOf(mode.charAt(0)) > -1 || - mode.substring(0, maxSearch).contains("+")) { - return "rw"; - } else { - return "r"; - } + return (reading ? "r" : "") + (writing ? "w" : "") + + (appending ? "a" : "") + (updating ? "+" : ""); } - final String file_read(int n) { - if (closed) - err_closed(); - StringBuffer data = new StringBuffer(); - try { - while (n != 0) { - String s = file.read(n); - int len = s.length(); - if (len == 0) - break; - data.append(s); - if (n > 0) { - n -= len; - if (n <= 0) - break; - } - } - } catch (IOException e) { - throw Py.IOError(e); - } - return data.toString(); + final synchronized String file_read(int n) { + checkClosed(); + return file.read(n); } public String read(int n) { @@ -744,26 +771,20 @@ return file_read(); } - final String file_readline(int max) { - if (closed) - err_closed(); - StringBuffer s = new StringBuffer(); - while (max < 0 || s.length() < max) { - int c; - try { - c = file.read(); - } catch (IOException e) { - throw Py.IOError(e); - } - if (c < 0) - break; - s.append((char)c); - if ((char)c == '\n') - break; - } - return s.toString(); + final synchronized int file_readinto(PyObject buf) { + checkClosed(); + return file.readinto(buf); } + public int readinto(PyObject buf) { + return file_readinto(buf); + } + + final synchronized String file_readline(int max) { + checkClosed(); + return file.readline(max); + } + public String readline(int max) { return file_readline(max); } @@ -776,22 +797,20 @@ return file_readline(-1); } - final PyObject file_readlines(int sizehint) { - if (closed) - err_closed(); + final synchronized PyObject file_readlines(int sizehint) { + checkClosed(); PyList list = new PyList(); - int bytesread = 0; - for (;;) { - String s = readline(); - int len = s.length(); - if (len == 0) + int count = 0; + do { + String line = file.readline(-1); + int len = line.length(); + if (len == 0) { // EOF break; - bytesread += len; - list.append(new PyString(s)); - if (sizehint > 0 && bytesread > sizehint) - break; - } + } + count += len; + list.append(new PyString(line)); + } while (sizehint <= 0 || count < sizehint); return list; } @@ -812,6 +831,7 @@ } final PyObject file___iter__() { + checkClosed(); return this; } @@ -819,11 +839,13 @@ return file___iternext__(); } - final PyObject file___iternext__() { - PyString s = new PyString(readline()); - if (s.__len__() == 0) + final synchronized PyObject file___iternext__() { + checkClosed(); + String next = file.readline(-1); + if (next.length() == 0) { return null; - return s; + } + return new PyString(next); } final PyObject file_next() { @@ -838,6 +860,7 @@ } final PyObject file_xreadlines() { + checkClosed(); return this; } @@ -846,40 +869,37 @@ } final void file_write(PyObject o) { - if(o instanceof PyUnicode) { + if (o instanceof PyUnicode) { // Call __str__ on unicode objects to encode them before writing file_write(o.__str__().string); - } else if(o instanceof PyString) { + } else if (o instanceof PyString) { file_write(((PyString)o).string); } else { throw Py.TypeError("write requires a string as its argument"); } } - final void file_write(String s) { - if (closed) - err_closed(); - try { - file.write(s); - softspace = false; - } catch (IOException e) { - throw Py.IOError(e); - } + final synchronized void file_write(String s) { + checkClosed(); + softspace = false; + file.write(s); } public void write(String s) { file_write(s); } - final void file_writelines(PyObject a) { + final synchronized void file_writelines(PyObject a) { + checkClosed(); PyObject iter = Py.iter(a, "writelines() requires an iterable argument"); PyObject item = null; - while((item = iter.__iternext__()) != null) { - if (!(item instanceof PyString)) + while ((item = iter.__iternext__()) != null) { + if (!(item instanceof PyString)) { throw Py.TypeError("writelines() argument must be a " + "sequence of strings"); - write(item.toString()); + } + file.write(item.toString()); } } @@ -887,28 +907,18 @@ file_writelines(a); } - final long file_tell() { - if (closed) - err_closed(); - try { - return file.tell(); - } catch (IOException e) { - throw Py.IOError(e); - } + final synchronized long file_tell() { + checkClosed(); + return file.tell(); } public long tell() { return file_tell(); } - final void file_seek(long pos, int how) { - if (closed) - err_closed(); - try { - file.seek(pos, how); - } catch (IOException e) { - throw Py.IOError(e); - } + final synchronized void file_seek(long pos, int how) { + checkClosed(); + file.seek(pos, how); } public void seek(long pos, int how) { @@ -923,79 +933,70 @@ file_seek(pos); } - final void file_flush() { - if (closed) - err_closed(); - try { - file.flush(); - } catch (IOException e) { - throw Py.IOError(e); - } + final synchronized void file_flush() { + checkClosed(); + file.flush(); } public void flush() { file_flush(); } - final void file_close() { + final synchronized void file_close() { if (closer != null) { closer.close(); closer = null; } else { - try { - file.close(); - } catch (IOException e) { - throw Py.IOError(e); - } + file.close(); } - closed = true; - file = new FileWrapper(); } public void close() { file_close(); } - final void file_truncate() { - try { - file.truncate(file.tell()); - } catch (IOException e) { - throw Py.IOError(e); - } + final synchronized void file_truncate() { + file.truncate(file.tell()); } public void truncate() { file_truncate(); } - final void file_truncate(long position) { - try { - file.truncate(position); - } catch (IOException e) { - throw Py.IOError(e); - } + final synchronized void file_truncate(long position) { + file.truncate(position); } public void truncate(long position) { file_truncate(position); } - // TBD: should this be removed? I think it's better to raise an - // AttributeError than an IOError here. - public PyObject fileno() { - throw Py.IOError("fileno() is not supported in jython"); + public boolean isatty() { + return file_isatty(); } + final boolean file_isatty() { + return file.isatty(); + } + + public int fileno() { + return file_fileno(); + } + + final int file_fileno() { + return file.fileno(); + } + final String file_toString() { StringBuffer s = new StringBuffer("<"); - if (closed) { + if (file.closed()) { s.append("closed "); } else { s.append("open "); } - s.append("file '"); - s.append(name); - s.append("', mode '"); + s.append("file "); + s.append(name.__repr__()); + s.append(", mode '"); s.append(mode); s.append("' "); s.append(Py.idstr(this)); @@ -1015,734 +1016,62 @@ return super.__nonzero__(); } - private void err_closed() { - throw Py.ValueError("I/O operation on closed file"); + private void checkClosed() { + file.checkClosed(); } public String getMode() { return mode; } - public String getName() { + public PyObject getName() { return name; } public boolean getClosed() { - return closed; + return file.closed(); } public PyObject getNewlines() { - if (!universal) { - return Py.None; - } - EnumSet newlineTypes = ((UniversalWrapper)file).getNewlineTypes(); - int size = newlineTypes.size(); - if (size == 0) { - return Py.None; - } else if (size == 1) { - String newline = ((Newline)newlineTypes.iterator().next()).getValue(); - return new PyString(newline); - } - - PyObject[] newlines = new PyObject[size]; - int i = 0; - for (Iterator newlineIter = newlineTypes.iterator(); newlineIter.hasNext();) { - String newline = ((Newline)newlineIter.next()).getValue(); - newlines[i] = new PyString(newline); - i++; - } - return new PyTuple(newlines); + return file.getNewlines(); } - protected void finalize() throws Throwable { - super.finalize(); - if (closer != null) { - closer.close(); - } + public PyObject getSoftspace() { + return softspace ? new PyInteger(1) : new PyInteger(0); } - private static class FileWrapper { - protected boolean reading; - protected boolean writing; - protected boolean binary; - - void setMode(String mode) { - reading = mode.indexOf('r') >= 0; - writing = mode.indexOf('w') >= 0 || mode.indexOf("+") >= 0 || - mode.indexOf('a') >= 0; - binary = mode.indexOf('b') >= 0; - } - - public String read(int n) throws IOException { - throw new IOException("file not open for reading"); - } - - public int read() throws IOException { - throw new IOException("file not open for reading"); - } - - public int available() throws IOException { - throw new IOException("file not open for reading"); - } - - public void unread(int c) throws IOException { - throw new IOException("file doesn't support unread"); - } - - public void write(String s) throws IOException { - throw new IOException("file not open for writing"); - } - - public long tell() throws IOException { - throw new IOException("file doesn't support tell/seek"); - } - - public void seek(long pos, int how) throws IOException { - throw new IOException("file doesn't support tell/seek"); - } - - public void flush() throws IOException { - } - - public void close() throws IOException { - } - - public void truncate(long position) throws IOException { - throw new IOException("file doesn't support truncate"); - } - - public Object __tojava__(Class cls) throws IOException { - return null; - } + public void setSoftspace(PyObject obj) { + softspace = obj.__nonzero__(); } - private static class InputStreamWrapper extends FileWrapper { - InputStream istream; - - public InputStreamWrapper(InputStream s) { - istream = s; - } - - public String read(int n) throws IOException { - if (n == 0) - // nothing to do - return ""; - if (n < 0) { - // read until we hit EOF - byte buf[] = new byte[1024]; - StringBuffer sbuf = new StringBuffer(); - for (int read=0; read >= 0; read=istream.read(buf)) - sbuf.append(PyString.from_bytes(buf, 0, read)); - return sbuf.toString(); - } - // read the next chunk available, but make sure it's at least - // one byte so as not to trip the `empty string' return value - // test done by the caller - //int avail = istream.available(); - //n = (n > avail) ? n : avail; - byte buf[] = new byte[n]; - int read = istream.read(buf); - if (read < 0) - // EOF encountered - return ""; - return PyString.from_bytes(buf, 0, read); - } - - public int read() throws IOException { - return istream.read(); - } - - public int available() throws IOException { - return istream.available(); - } - - public void unread(int c) throws IOException { - ((PushbackInputStream)istream).unread(c); - } - - public void close() throws IOException { - istream.close(); - } - - public Object __tojava__(Class cls) throws IOException { - if (InputStream.class.isAssignableFrom(cls)) - return is... [truncated message content] |