[Jython-checkins] jython: Allow struct unpack and unpack_from bytearray and buffer (GH-121)

jeff.allen jython-checkins at python.org
Tue Apr 9 01:15:01 EDT 2019


https://hg.python.org/jython/rev/66091cb89839
changeset:   8235:66091cb89839
user:        Ray Ferguson <github.public at devendortech.com>
date:        Mon Apr 08 22:22:35 2019 +0100
summary:
  Allow struct unpack and unpack_from bytearray and buffer (GH-121)

struct module from CPython 2.7.6 supports unpack from a bytearray or buffer.
This patch adds support for unpack() and unpack_from() for the additional types
and adds test cases based on tests/test_struct.py which is not run in regrtest
by default.

Modified by Jeff from https://github.com/jythontools/jython/pull/121

files:
  Lib/test/test_struct_jy.py           |  158 +++++++++++++++
  NEWS                                 |    1 +
  src/org/python/core/Py2kBuffer.java  |    7 +-
  src/org/python/core/PyByteArray.java |   11 +-
  src/org/python/modules/struct.java   |   27 ++
  5 files changed, 200 insertions(+), 4 deletions(-)


diff --git a/Lib/test/test_struct_jy.py b/Lib/test/test_struct_jy.py
new file mode 100644
--- /dev/null
+++ b/Lib/test/test_struct_jy.py
@@ -0,0 +1,158 @@
+import unittest
+from test import test_support
+import struct
+
+import sys
+ISBIGENDIAN = sys.byteorder == "big"
+
+class StructTests(unittest.TestCase): # (format, argument, big-endian result, little-endian result, asymmetric)
+    _tests = [
+        ('c', 'a', 'a', 'a', 0),
+        ('xc', 'a', '\0a', '\0a', 0),
+        ('cx', 'a', 'a\0', 'a\0', 0),
+        ('s', 'a', 'a', 'a', 0),
+        ('0s', 'helloworld', '', '', 1),
+        ('1s', 'helloworld', 'h', 'h', 1),
+        ('9s', 'helloworld', 'helloworl', 'helloworl', 1),
+        ('10s', 'helloworld', 'helloworld', 'helloworld', 0),
+        ('11s', 'helloworld', 'helloworld\0', 'helloworld\0', 1),
+        ('20s', 'helloworld', 'helloworld'+10*'\0', 'helloworld'+10*'\0', 1),
+        ('b', 7, '\7', '\7', 0),
+        ('b', -7, '\371', '\371', 0),
+        ('B', 7, '\7', '\7', 0),
+        ('B', 249, '\371', '\371', 0),
+        ('h', 700, '\002\274', '\274\002', 0),
+        ('h', -700, '\375D', 'D\375', 0),
+        ('H', 700, '\002\274', '\274\002', 0),
+        ('H', 0x10000-700, '\375D', 'D\375', 0),
+        ('i', 70000000, '\004,\035\200', '\200\035,\004', 0),
+        ('i', -70000000, '\373\323\342\200', '\200\342\323\373', 0),
+        ('I', 70000000L, '\004,\035\200', '\200\035,\004', 0),
+        ('I', 0x100000000L-70000000, '\373\323\342\200', '\200\342\323\373', 0),
+        ('l', 70000000, '\004,\035\200', '\200\035,\004', 0),
+        ('l', -70000000, '\373\323\342\200', '\200\342\323\373', 0),
+        ('L', 70000000L, '\004,\035\200', '\200\035,\004', 0),
+        ('L', 0x100000000L-70000000, '\373\323\342\200', '\200\342\323\373', 0),
+        ('f', 2.0, '@\000\000\000', '\000\000\000@', 0),
+        ('d', 2.0, '@\000\000\000\000\000\000\000',
+                   '\000\000\000\000\000\000\000@', 0),
+        ('f', -2.0, '\300\000\000\000', '\000\000\000\300', 0),
+        ('d', -2.0, '\300\000\000\000\000\000\000\000',
+                   '\000\000\000\000\000\000\000\300', 0),
+    ]
+
+    def test_struct(self):
+        for fmt, arg, big, lil, asy in self._tests:
+            for (xfmt, exp) in [('>'+fmt, big), ('!'+fmt, big), ('<'+fmt, lil),
+                                ('='+fmt, ISBIGENDIAN and big or lil)]:
+                res = struct.pack(xfmt, arg)
+                self.assertEqual(res,exp,msg="pack(%r, %r) -> %r # expected %r" %
+                                             (fmt, arg, res, exp))
+                n=struct.calcsize(xfmt)
+                self.assertEqual(n, len(res),msg="calcsize(%r) -> %d # expected %d" %
+                                                                      (xfmt, n, len(res)))
+                rev = struct.unpack(xfmt, res)[0]
+                if asy:
+                    self.assertNotEqual(arg,rev,msg="unpack(%r, %r) -> (%r,) # expected (%r,)" %
+                                                    (fmt, res, rev, exp))
+                else:
+                    self.assertEqual(arg,rev,msg="unpack(%r, %r) -> (%r,) # expected (%r,)" %
+                                                 (fmt, res, rev, arg))
+
+    def test_struct_unpack_bytearray(self):
+        for fmt, arg, big, lil, asy in self._tests:
+            for (xfmt, exp) in [('>'+fmt, big), ('!'+fmt, big), ('<'+fmt, lil),
+                                ('='+fmt, ISBIGENDIAN and big or lil)]:
+                res = struct.pack(xfmt, arg)
+                self.assertEqual(res,exp,msg="pack(%r, %r) -> %r # expected %r" %
+                                             (fmt, arg, res, exp))
+                n=struct.calcsize(xfmt)
+                self.assertEqual(n, len(res),msg="calcsize(%r) -> %d # expected %d" %
+                                                                      (xfmt, n, len(res)))
+                rev = struct.unpack(xfmt, bytearray(res))[0]
+                if asy:
+                    self.assertNotEqual(arg,rev,msg="unpack(%r, %r) -> (%r,) # expected (%r,)" %
+                                                    (fmt, res, rev, exp))
+                else:
+                    self.assertEqual(arg,rev,msg="unpack(%r, %r) -> (%r,) # expected (%r,)" %
+                                                 (fmt, res, rev, arg))
+
+    def test_struct_unpack_buffer(self):
+        for fmt, arg, big, lil, asy in self._tests:
+            for (xfmt, exp) in [('>'+fmt, big), ('!'+fmt, big), ('<'+fmt, lil),
+                                ('='+fmt, ISBIGENDIAN and big or lil)]:
+                res = struct.pack(xfmt, arg)
+                self.assertEqual(res,exp,msg="pack(%r, %r) -> %r # expected %r" %
+                                             (fmt, arg, res, exp))
+                n=struct.calcsize(xfmt)
+                self.assertEqual(n, len(res),msg="calcsize(%r) -> %d # expected %d" %
+                                                                      (xfmt, n, len(res)))
+                rev = struct.unpack(xfmt, buffer(res))[0]
+                if asy:
+                    self.assertNotEqual(arg,rev,msg="unpack(%r, %r) -> (%r,) # expected (%r,)" %
+                                                    (fmt, res, rev, exp))
+                else:
+                    self.assertEqual(arg,rev,msg="unpack(%r, %r) -> (%r,) # expected (%r,)" %
+                                                 (fmt, res, rev, arg))
+    def test_struct_unpack_from(self):
+        for fmt, arg, big, lil, asy in self._tests:
+            for (xfmt, exp) in [('>'+fmt, big), ('!'+fmt, big), ('<'+fmt, lil),
+                                ('='+fmt, ISBIGENDIAN and big or lil)]:
+                res = struct.pack(xfmt, arg)
+                self.assertEqual(res,exp,msg="pack(%r, %r) -> %r # expected %r" %
+                                             (fmt, arg, res, exp))
+                n=struct.calcsize(xfmt)
+                self.assertEqual(n, len(res),msg="calcsize(%r) -> %d # expected %d" %
+                                                                      (xfmt, n, len(res)))
+                rev = struct.unpack_from(xfmt, res)[0]
+                if asy:
+                    self.assertNotEqual(arg,rev,msg="unpack(%r, %r) -> (%r,) # expected (%r,)" %
+                                                    (fmt, res, rev, exp))
+                else:
+                    self.assertEqual(arg,rev,msg="unpack(%r, %r) -> (%r,) # expected (%r,)" %
+                                                 (fmt, res, rev, arg))
+
+    def test_struct_unpack_from_bytearray(self):
+        for fmt, arg, big, lil, asy in self._tests:
+            for (xfmt, exp) in [('>'+fmt, big), ('!'+fmt, big), ('<'+fmt, lil),
+                                ('='+fmt, ISBIGENDIAN and big or lil)]:
+                res = struct.pack(xfmt, arg)
+                self.assertEqual(res,exp,msg="pack(%r, %r) -> %r # expected %r" %
+                                             (fmt, arg, res, exp))
+                n=struct.calcsize(xfmt)
+                self.assertEqual(n, len(res),msg="calcsize(%r) -> %d # expected %d" %
+                                                                      (xfmt, n, len(res)))
+                rev = struct.unpack_from(xfmt, bytearray(res))[0]
+                if asy:
+                    self.assertNotEqual(arg,rev,msg="unpack(%r, %r) -> (%r,) # expected (%r,)" %
+                                                    (fmt, res, rev, exp))
+                else:
+                    self.assertEqual(arg,rev,msg="unpack(%r, %r) -> (%r,) # expected (%r,)" %
+                                                 (fmt, res, rev, arg))
+
+    def test_struct_unpack_from_buffer(self):
+        for fmt, arg, big, lil, asy in self._tests:
+            for (xfmt, exp) in [('>'+fmt, big), ('!'+fmt, big), ('<'+fmt, lil),
+                                ('='+fmt, ISBIGENDIAN and big or lil)]:
+                res = struct.pack(xfmt, arg)
+                self.assertEqual(res,exp,msg="pack(%r, %r) -> %r # expected %r" %
+                                             (fmt, arg, res, exp))
+                n=struct.calcsize(xfmt)
+                self.assertEqual(n, len(res),msg="calcsize(%r) -> %d # expected %d" %
+                                                                      (xfmt, n, len(res)))
+                rev = struct.unpack_from(xfmt, buffer(res))[0]
+                if asy:
+                    self.assertNotEqual(arg,rev,msg="unpack(%r, %r) -> (%r,) # expected (%r,)" %
+                                                    (fmt, res, rev, exp))
+                else:
+                    self.assertEqual(arg,rev,msg="unpack(%r, %r) -> (%r,) # expected (%r,)" %
+                                                 (fmt, res, rev, arg))
+
+
+
+
+def test_main():
+    test_support.run_unittest(__name__)
+
+if __name__ == "__main__":
+    test_main()
diff --git a/NEWS b/NEWS
--- a/NEWS
+++ b/NEWS
@@ -5,6 +5,7 @@
 
 Development tip
   Bugs fixed
+    - [ GH-121 ] Allow struct unpack and unpack_from bytearray and buffer
     - [ 2635 ] AST.lineno ignored by compile
     - [ 2744 ] Support buffer type in marshal.dump(s)
     - [ 2077 ] marshal doesn't raise error when fed unmarshalable object
diff --git a/src/org/python/core/Py2kBuffer.java b/src/org/python/core/Py2kBuffer.java
--- a/src/org/python/core/Py2kBuffer.java
+++ b/src/org/python/core/Py2kBuffer.java
@@ -203,8 +203,13 @@
 
     @ExposedMethod(doc = BuiltinDocs.buffer___str___doc)
     final PyString buffer___str__() {
+        return new PyString(toString());
+    }
+
+    @Override
+    public String toString() {
         try (PyBuffer buf = getBuffer()) {
-            return new PyString(buf.toString());
+            return buf.toString();
         }
     }
 
diff --git a/src/org/python/core/PyByteArray.java b/src/org/python/core/PyByteArray.java
--- a/src/org/python/core/PyByteArray.java
+++ b/src/org/python/core/PyByteArray.java
@@ -2014,12 +2014,17 @@
      */
     @Override
     public String toString() {
-        return bytearray_repr();
+        return this.asString();
+    }
+
+    @Override
+    public PyString __repr__(){
+       return bytearray___repr__();
     }
 
     @ExposedMethod(names = {"__repr__"}, doc = BuiltinDocs.bytearray___repr___doc)
-    final synchronized String bytearray_repr() {
-        return basebytes_repr("bytearray(b", ")");
+    final synchronized PyString bytearray___repr__() {
+        return new PyString(basebytes_repr("bytearray(b", ")"));
     }
 
     /**
diff --git a/src/org/python/modules/struct.java b/src/org/python/modules/struct.java
--- a/src/org/python/modules/struct.java
+++ b/src/org/python/modules/struct.java
@@ -21,6 +21,8 @@
 import java.math.BigInteger;
 import org.python.core.ClassDictInit;
 import org.python.core.PyArray;
+import org.python.core.PyByteArray;
+import org.python.core.Py2kBuffer;
 
 /**
  * This module performs conversions between Python values and C
@@ -1097,6 +1099,31 @@
          return unpack(f, size, format, new ByteStream(string));
     }
     
+    public static PyTuple unpack(String format, Py2kBuffer buffer){
+        return unpack(format, buffer.toString());
+    }
+
+    public static PyTuple unpack(String format, PyByteArray bytearray) {
+        /* bytearray is added in 2.7.7 */
+        return unpack(format, bytearray.toString());
+    }
+
+    public static PyTuple unpack_from(String format, Py2kBuffer buffer) {
+        return unpack_from(format, buffer.toString(), 0);
+    }
+
+    public static PyTuple unpack_from(String format, PyByteArray bytearray) {
+        return unpack_from(format, bytearray.toString(), 0);
+    }
+
+    public static PyTuple unpack_from(String format, Py2kBuffer buffer, int offset) {
+        return unpack_from(format, buffer.toString(), offset);
+    }
+
+    public static PyTuple unpack_from(String format, PyByteArray bytearray, int offset) {
+        return unpack_from(format, bytearray.toString(), offset);
+    }
+
     public static PyTuple unpack_from(String format, String string) {
         return unpack_from(format, string, 0);   
     }

-- 
Repository URL: https://hg.python.org/jython


More information about the Jython-checkins mailing list