bpo-33073: Adding as_integer_ratio to ints. (GH-8750)

diff --git a/Doc/library/stdtypes.rst b/Doc/library/stdtypes.rst
index fd59a51..5a133e3 100644
--- a/Doc/library/stdtypes.rst
+++ b/Doc/library/stdtypes.rst
@@ -537,6 +537,14 @@
 
     .. versionadded:: 3.2
 
+.. method:: int.as_integer_ratio()
+
+   Return a pair of integers whose ratio is exactly equal to the original
+   integer and with a positive denominator. The integer ratio of integers
+   (whole numbers) is always the integer as the numerator and ``1`` as the
+   denominator.
+
+   .. versionadded:: 3.8
 
 Additional Methods on Float
 ---------------------------
diff --git a/Doc/whatsnew/3.8.rst b/Doc/whatsnew/3.8.rst
index b2475c7..38b8623 100644
--- a/Doc/whatsnew/3.8.rst
+++ b/Doc/whatsnew/3.8.rst
@@ -91,6 +91,10 @@
   was lifted.
   (Contributed by Serhiy Storchaka in :issue:`32489`.)
 
+* The ``int`` type now has a new ``as_integer_ratio`` method compatible
+  with the existing ``float.as_integer_ratio`` method.
+  (Contributed by Lisa Roach in :issue:`33073`.)
+
 * Added support of ``\N{name}`` escapes in :mod:`regular expressions <re>`.
   (Contributed by Jonathan Eunice and Serhiy Storchaka in :issue:`30688`.)
 
diff --git a/Lib/test/test_doctest.py b/Lib/test/test_doctest.py
index 83941c1..797bdb8 100644
--- a/Lib/test/test_doctest.py
+++ b/Lib/test/test_doctest.py
@@ -665,7 +665,7 @@
     True
     >>> real_tests = [t for t in tests if len(t.examples) > 0]
     >>> len(real_tests) # objects that actually have doctests
-    8
+    9
     >>> for t in real_tests:
     ...     print('{}  {}'.format(len(t.examples), t.name))
     ...
@@ -675,6 +675,7 @@
     2  builtins.float.hex
     1  builtins.hex
     1  builtins.int
+    3  builtins.int.as_integer_ratio
     2  builtins.int.bit_length
     1  builtins.oct
 
diff --git a/Lib/test/test_long.py b/Lib/test/test_long.py
index 8472889..7c883ba 100644
--- a/Lib/test/test_long.py
+++ b/Lib/test/test_long.py
@@ -3,6 +3,7 @@
 
 import sys
 
+import enum
 import random
 import math
 import array
@@ -1349,6 +1350,37 @@
                 self.assertEqual(type(value << shift), int)
                 self.assertEqual(type(value >> shift), int)
 
+    def test_as_integer_ratio(self):
+        tests = [10, 0, -10, 1]
+        for value in tests:
+            numerator, denominator = value.as_integer_ratio()
+            self.assertEqual((numerator, denominator), (value, 1))
+            self.assertIsInstance(numerator, int)
+            self.assertIsInstance(denominator, int)
+
+    def test_as_integer_ratio_maxint(self):
+        x = sys.maxsize + 1
+        self.assertEqual(x.as_integer_ratio()[0], x)
+
+    def test_as_integer_ratio_bool(self):
+        self.assertEqual(True.as_integer_ratio(), (1, 1))
+        self.assertEqual(False.as_integer_ratio(), (0, 1))
+        self.assertEqual(type(True.as_integer_ratio()[0]), int)
+        self.assertEqual(type(False.as_integer_ratio()[0]), int)
+
+    def test_as_integer_ratio_int_enum(self):
+        class Foo(enum.IntEnum):
+            X = 42
+        self.assertEqual(Foo.X.as_integer_ratio(), (42, 1))
+        self.assertEqual(type(Foo.X.as_integer_ratio()[0]), int)
+
+    def test_as_integer_ratio_int_flag(self):
+        class Foo(enum.IntFlag):
+            R = 1 << 2
+        self.assertEqual(Foo.R.as_integer_ratio(), (4, 1))
+        self.assertEqual(type(Foo.R.as_integer_ratio()[0]), int)
+
+
 
 if __name__ == "__main__":
     unittest.main()
diff --git a/Misc/ACKS b/Misc/ACKS
index 9698535..a29ff60 100644
--- a/Misc/ACKS
+++ b/Misc/ACKS
@@ -1350,6 +1350,7 @@
 Mohd Sanad Zaki Rizvi
 Davide Rizzo
 Anthony Roach
+Lisa Roach
 Carl Robben
 Ben Roberts
 Mark Roberts
diff --git a/Misc/NEWS.d/next/Core and Builtins/2018-08-12-16-03-58.bpo-33073.XWu1Jh.rst b/Misc/NEWS.d/next/Core and Builtins/2018-08-12-16-03-58.bpo-33073.XWu1Jh.rst
new file mode 100644
index 0000000..ce9b612
--- /dev/null
+++ b/Misc/NEWS.d/next/Core and Builtins/2018-08-12-16-03-58.bpo-33073.XWu1Jh.rst
@@ -0,0 +1 @@
+Added as_integer_ratio to ints to make them more interoperable with floats.
diff --git a/Objects/clinic/longobject.c.h b/Objects/clinic/longobject.c.h
index 14f5515..0e70fe5 100644
--- a/Objects/clinic/longobject.c.h
+++ b/Objects/clinic/longobject.c.h
@@ -118,6 +118,34 @@
     return int_bit_length_impl(self);
 }
 
+PyDoc_STRVAR(int_as_integer_ratio__doc__,
+"as_integer_ratio($self, /)\n"
+"--\n"
+"\n"
+"Return integer ratio.\n"
+"\n"
+"Return a pair of integers, whose ratio is exactly equal to the original int\n"
+"and with a positive denominator.\n"
+"\n"
+">>> (10).as_integer_ratio()\n"
+"(10, 1)\n"
+">>> (-10).as_integer_ratio()\n"
+"(-10, 1)\n"
+">>> (0).as_integer_ratio()\n"
+"(0, 1)");
+
+#define INT_AS_INTEGER_RATIO_METHODDEF    \
+    {"as_integer_ratio", (PyCFunction)int_as_integer_ratio, METH_NOARGS, int_as_integer_ratio__doc__},
+
+static PyObject *
+int_as_integer_ratio_impl(PyObject *self);
+
+static PyObject *
+int_as_integer_ratio(PyObject *self, PyObject *Py_UNUSED(ignored))
+{
+    return int_as_integer_ratio_impl(self);
+}
+
 PyDoc_STRVAR(int_to_bytes__doc__,
 "to_bytes($self, /, length, byteorder, *, signed=False)\n"
 "--\n"
@@ -211,4 +239,4 @@
 exit:
     return return_value;
 }
-/*[clinic end generated code: output=fd64beb83bd16df3 input=a9049054013a1b77]*/
+/*[clinic end generated code: output=6d5e92d7dc803751 input=a9049054013a1b77]*/
diff --git a/Objects/longobject.c b/Objects/longobject.c
index 399d354..98ff9a8 100644
--- a/Objects/longobject.c
+++ b/Objects/longobject.c
@@ -5261,6 +5261,36 @@
 #endif
 
 /*[clinic input]
+int.as_integer_ratio
+
+Return integer ratio.
+
+Return a pair of integers, whose ratio is exactly equal to the original int
+and with a positive denominator.
+
+>>> (10).as_integer_ratio()
+(10, 1)
+>>> (-10).as_integer_ratio()
+(-10, 1)
+>>> (0).as_integer_ratio()
+(0, 1)
+[clinic start generated code]*/
+
+static PyObject *
+int_as_integer_ratio_impl(PyObject *self)
+/*[clinic end generated code: output=e60803ae1cc8621a input=55ce3058e15de393]*/
+{
+    if PyLong_CheckExact(self) {
+        return PyTuple_Pack(2, self, _PyLong_One);
+    } else {
+        PyObject *numerator = _PyLong_Copy(self);
+        PyObject *ratio_tuple = PyTuple_Pack(2, numerator, _PyLong_One);
+        Py_DECREF(numerator);
+        return ratio_tuple;
+    }
+}
+
+/*[clinic input]
 int.to_bytes
 
     length: Py_ssize_t
@@ -5392,6 +5422,7 @@
 #endif
     INT_TO_BYTES_METHODDEF
     INT_FROM_BYTES_METHODDEF
+    INT_AS_INTEGER_RATIO_METHODDEF
     {"__trunc__",       long_long_meth, METH_NOARGS,
      "Truncating an Integral returns itself."},
     {"__floor__",       long_long_meth, METH_NOARGS,