mirror of
https://github.com/python/cpython.git
synced 2025-12-08 06:10:17 +00:00
gh-131531: android.py enhancements to support cibuildwheel (#132870)
Modifies the environment handling and execution arguments of the Android management script to support the compilation of third-party binaries, and the use of the testbed to invoke third-party test code. Co-authored-by: Adam Turner <9087854+AA-Turner@users.noreply.github.com> Co-authored-by: Russell Keith-Magee <russell@keith-magee.com>
This commit is contained in:
parent
6b77af257c
commit
2e1544fd2b
10 changed files with 239 additions and 90 deletions
|
|
@ -85,7 +85,7 @@ android {
|
|||
|
||||
minSdk = androidEnvFile.useLines {
|
||||
for (line in it) {
|
||||
"""api_level:=(\d+)""".toRegex().find(line)?.let {
|
||||
"""ANDROID_API_LEVEL:=(\d+)""".toRegex().find(line)?.let {
|
||||
return@useLines it.groupValues[1].toInt()
|
||||
}
|
||||
}
|
||||
|
|
@ -205,11 +205,29 @@ androidComponents.onVariants { variant ->
|
|||
|
||||
into("site-packages") {
|
||||
from("$projectDir/src/main/python")
|
||||
|
||||
val sitePackages = findProperty("python.sitePackages") as String?
|
||||
if (!sitePackages.isNullOrEmpty()) {
|
||||
if (!file(sitePackages).exists()) {
|
||||
throw GradleException("$sitePackages does not exist")
|
||||
}
|
||||
from(sitePackages)
|
||||
}
|
||||
}
|
||||
|
||||
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
|
||||
exclude("**/__pycache__")
|
||||
}
|
||||
|
||||
into("cwd") {
|
||||
val cwd = findProperty("python.cwd") as String?
|
||||
if (!cwd.isNullOrEmpty()) {
|
||||
if (!file(cwd).exists()) {
|
||||
throw GradleException("$cwd does not exist")
|
||||
}
|
||||
from(cwd)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -17,11 +17,11 @@ class PythonSuite {
|
|||
fun testPython() {
|
||||
val start = System.currentTimeMillis()
|
||||
try {
|
||||
val context =
|
||||
val status = PythonTestRunner(
|
||||
InstrumentationRegistry.getInstrumentation().targetContext
|
||||
val args =
|
||||
InstrumentationRegistry.getArguments().getString("pythonArgs", "")
|
||||
val status = PythonTestRunner(context).run(args)
|
||||
).run(
|
||||
InstrumentationRegistry.getArguments()
|
||||
)
|
||||
assertEquals(0, status)
|
||||
} finally {
|
||||
// Make sure the process lives long enough for the test script to
|
||||
|
|
|
|||
|
|
@ -15,17 +15,29 @@ class MainActivity : AppCompatActivity() {
|
|||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setContentView(R.layout.activity_main)
|
||||
val status = PythonTestRunner(this).run("-W -uall")
|
||||
val status = PythonTestRunner(this).run("-m", "test", "-W -uall")
|
||||
findViewById<TextView>(R.id.tvHello).text = "Exit status $status"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class PythonTestRunner(val context: Context) {
|
||||
/** @param args Extra arguments for `python -m test`.
|
||||
* @return The Python exit status: zero if the tests passed, nonzero if
|
||||
* they failed. */
|
||||
fun run(args: String = "") : Int {
|
||||
fun run(instrumentationArgs: Bundle) = run(
|
||||
instrumentationArgs.getString("pythonMode")!!,
|
||||
instrumentationArgs.getString("pythonModule")!!,
|
||||
instrumentationArgs.getString("pythonArgs") ?: "",
|
||||
)
|
||||
|
||||
/** Run Python.
|
||||
*
|
||||
* @param mode Either "-c" or "-m".
|
||||
* @param module Python statements for "-c" mode, or a module name for
|
||||
* "-m" mode.
|
||||
* @param args Arguments to add to sys.argv. Will be parsed by `shlex.split`.
|
||||
* @return The Python exit status: zero on success, nonzero on failure. */
|
||||
fun run(mode: String, module: String, args: String) : Int {
|
||||
Os.setenv("PYTHON_MODE", mode, true)
|
||||
Os.setenv("PYTHON_MODULE", module, true)
|
||||
Os.setenv("PYTHON_ARGS", args, true)
|
||||
|
||||
// Python needs this variable to help it find the temporary directory,
|
||||
|
|
@ -36,8 +48,9 @@ class PythonTestRunner(val context: Context) {
|
|||
System.loadLibrary("main_activity")
|
||||
redirectStdioToLogcat()
|
||||
|
||||
// The main module is in src/main/python/main.py.
|
||||
return runPython(pythonHome.toString(), "main")
|
||||
// The main module is in src/main/python. We don't simply call it
|
||||
// "main", as that could clash with third-party test code.
|
||||
return runPython(pythonHome.toString(), "android_testbed_main")
|
||||
}
|
||||
|
||||
private fun extractAssets() : File {
|
||||
|
|
|
|||
|
|
@ -26,7 +26,23 @@
|
|||
# test_signals in test_threadsignals.py.
|
||||
signal.pthread_sigmask(signal.SIG_UNBLOCK, [signal.SIGUSR1])
|
||||
|
||||
mode = os.environ["PYTHON_MODE"]
|
||||
module = os.environ["PYTHON_MODULE"]
|
||||
sys.argv[1:] = shlex.split(os.environ["PYTHON_ARGS"])
|
||||
|
||||
# The test module will call sys.exit to indicate whether the tests passed.
|
||||
runpy.run_module("test")
|
||||
cwd = f"{sys.prefix}/cwd"
|
||||
if not os.path.exists(cwd):
|
||||
# Empty directories are lost in the asset packing/unpacking process.
|
||||
os.mkdir(cwd)
|
||||
os.chdir(cwd)
|
||||
|
||||
if mode == "-c":
|
||||
# In -c mode, sys.path starts with an empty string, which means whatever the current
|
||||
# working directory is at the moment of each import.
|
||||
sys.path.insert(0, "")
|
||||
exec(module, {})
|
||||
elif mode == "-m":
|
||||
sys.path.insert(0, os.getcwd())
|
||||
runpy.run_module(module, run_name="__main__", alter_sys=True)
|
||||
else:
|
||||
raise ValueError(f"unknown mode: {mode}")
|
||||
Loading…
Add table
Add a link
Reference in a new issue