diff -r 64ed56fbc5e7 Lib/test/test_sys.py --- a/Lib/test/test_sys.py Sat Jun 25 03:06:58 2016 +0000 +++ b/Lib/test/test_sys.py Sat Jul 02 16:34:07 2016 +0200 @@ -763,6 +763,14 @@ self.assertEqual(sys.implementation.name, sys.implementation.name.lower()) + @unittest.skipUnless(hasattr(sys.implementation, "_android_api"), + "not an android platform") + def test_is_android(self): + # Use an heuristic, the shell on Android is at /system/bin/sh. + proc = subprocess.run(['/system/bin/sh', '-c', 'echo OK'], + stdout=subprocess.PIPE) + self.assertIn(b'OK', proc.stdout) + @test.support.cpython_only def test_debugmallocstats(self): # Test sys._debugmallocstats() diff -r 64ed56fbc5e7 Misc/NEWS --- a/Misc/NEWS Sat Jun 25 03:06:58 2016 +0000 +++ b/Misc/NEWS Sat Jul 02 16:34:07 2016 +0200 @@ -88,6 +88,9 @@ Build ----- +- Issue #27442: Expose the Android API level that python was built against, in + sys.implementation as '_android_api'. + - Issue #26930: Update Windows builds to use OpenSSL 1.0.2h. - Issue #23968: Rename the platform directory from plat-$(MACHDEP) to diff -r 64ed56fbc5e7 Python/sysmodule.c --- a/Python/sysmodule.c Sat Jun 25 03:06:58 2016 +0000 +++ b/Python/sysmodule.c Sat Jul 02 16:34:07 2016 +0200 @@ -1653,58 +1653,57 @@ #undef MINOR #undef TAG +static int +add_impl_info(PyObject *dict, const char *key, PyObject *value) +{ + int res; + if (value == NULL) + return -1; + res = PyDict_SetItemString(dict, key, value); + Py_DECREF(value); + return res; +} + +static int +add_impl_info_char(PyObject *dict, const char *key, const char *value) +{ + return add_impl_info(dict, key, PyUnicode_FromString(value)); +} + +static int +add_impl_info_long(PyObject *dict, const char *key, long value) +{ + return add_impl_info(dict, key, PyLong_FromLong(value)); +} + static PyObject * make_impl_info(PyObject *version_info) { - int res; - PyObject *impl_info, *value, *ns; + PyObject *impl_info, *ns; impl_info = PyDict_New(); if (impl_info == NULL) return NULL; /* populate the dict */ - - value = PyUnicode_FromString(_PySys_ImplName); - if (value == NULL) - goto error; - res = PyDict_SetItemString(impl_info, "name", value); - Py_DECREF(value); - if (res < 0) - goto error; - - value = PyUnicode_FromString(_PySys_ImplCacheTag); - if (value == NULL) - goto error; - res = PyDict_SetItemString(impl_info, "cache_tag", value); - Py_DECREF(value); - if (res < 0) + if (add_impl_info_char(impl_info, "name", _PySys_ImplName) < 0) goto error; - - res = PyDict_SetItemString(impl_info, "version", version_info); - if (res < 0) - goto error; - - value = PyLong_FromLong(PY_VERSION_HEX); - if (value == NULL) + if (add_impl_info_char(impl_info, "cache_tag", _PySys_ImplCacheTag) < 0) goto error; - res = PyDict_SetItemString(impl_info, "hexversion", value); - Py_DECREF(value); - if (res < 0) + if (PyDict_SetItemString(impl_info, "version", version_info) < 0) goto error; - + if (add_impl_info_long(impl_info, "hexversion", PY_VERSION_HEX) < 0) + goto error; #ifdef MULTIARCH - value = PyUnicode_FromString(MULTIARCH); - if (value == NULL) + if (add_impl_info_char(impl_info, "_multiarch", MULTIARCH) < 0) goto error; - res = PyDict_SetItemString(impl_info, "_multiarch", value); - Py_DECREF(value); - if (res < 0) +#endif +#ifdef __ANDROID__ + if (add_impl_info_long(impl_info, "_android_api", __ANDROID_API__) < 0) goto error; #endif /* dict ready */ - ns = _PyNamespace_New(impl_info); Py_DECREF(impl_info); return ns;