Repository: pika/pika

Issue:
Python int type does not fit into struct 'i' format
https://github.com/pika/pika/blob/master/pika/data.py#L118-L123

I'm getting a "struct.error: 'i' format requires -2147483648 <= number <= 2147483647" where my value is 2592000000. That value fits into a Python int, which is `long` and on our platform is 64-bit wide, while struct 'i' format is defined as strictly 32-bit. I can work around that by explicitly casting to `long`, but it is a bug in pika nonetheless.

Discussion:

Patch:
diff --git a/pika/data.py b/pika/data.py
index fe35e37..da6ab63 100644
--- a/pika/data.py
+++ b/pika/data.py
@@ -2,6 +2,8 @@
 import struct
 import decimal
 import calendar
+import warnings
+
 from datetime import datetime
 
 from pika import exceptions
@@ -119,8 +121,16 @@ def encode_value(pieces, value):
         pieces.append(struct.pack('>cq', b'l', value))
         return 9
     elif isinstance(value, int):
-        pieces.append(struct.pack('>ci', b'I', value))
-        return 5
+        with warnings.catch_warnings():
+            warnings.filterwarnings('error')
+            try:
+                p = struct.pack('>ci', b'I', value)
+                pieces.append(p)
+                return 5
+            except (struct.error, DeprecationWarning):
+                p = struct.pack('>cq', b'l', long(value))
+                pieces.append(p)
+                return 9
     elif isinstance(value, decimal.Decimal):
         value = value.normalize()
         if value.as_tuple().exponent < 0:


Test patch:
diff --git a/tests/unit/data_tests.py b/tests/unit/data_tests.py
index f14decc..eccb0ef 100644
--- a/tests/unit/data_tests.py
+++ b/tests/unit/data_tests.py
@@ -24,14 +24,15 @@ from pika.compat import long
 class DataTests(unittest.TestCase):
 
     FIELD_TBL_ENCODED = (
-        b'\x00\x00\x00\xbb'
+        b'\x00\x00\x00\xcb'
         b'\x05arrayA\x00\x00\x00\x0fI\x00\x00\x00\x01I\x00\x00\x00\x02I\x00\x00\x00\x03'
         b'\x07boolvalt\x01'
         b'\x07decimalD\x02\x00\x00\x01:'
         b'\x0bdecimal_tooD\x00\x00\x00\x00d'
         b'\x07dictvalF\x00\x00\x00\x0c\x03fooS\x00\x00\x00\x03bar'
         b'\x06intvalI\x00\x00\x00\x01'
-        b'\x07longvall\x00\x00\x00\x006e&U'
+        b'\x06bigint\x6c\x00\x00\x00\x00\x9a\x7e\xc8\x00'
+        b'\x07longval\x6c\x00\x00\x00\x00\x36\x65\x26\x55'
         b'\x04nullV'
         b'\x06strvalS\x00\x00\x00\x04Test'
         b'\x0ctimestampvalT\x00\x00\x00\x00Ec)\x92'
@@ -44,7 +45,8 @@ class DataTests(unittest.TestCase):
         ('decimal', decimal.Decimal('3.14')),
         ('decimal_too', decimal.Decimal('100')),
         ('dictval', {'foo': 'bar'}),
-        ('intval', 1)	,
+        ('intval', 1),
+        ('bigint', 2592000000),
         ('longval', long(912598613)),
         ('null', None),
         ('strval', 'Test'),
@@ -60,7 +62,7 @@ class DataTests(unittest.TestCase):
     def test_encode_table_bytes(self):
         result = []
         byte_count = data.encode_table(result, self.FIELD_TBL_VALUE)
-        self.assertEqual(byte_count, 191)
+        self.assertEqual(byte_count, 207)
 
     def test_decode_table(self):
         value, byte_count = data.decode_table(self.FIELD_TBL_ENCODED, 0)
@@ -68,7 +70,7 @@ class DataTests(unittest.TestCase):
 
     def test_decode_table_bytes(self):
         value, byte_count = data.decode_table(self.FIELD_TBL_ENCODED, 0)
-        self.assertEqual(byte_count, 191)
+        self.assertEqual(byte_count, 207)
 
     def test_encode_raises(self):
         self.assertRaises(exceptions.UnsupportedAMQPFieldException,