Skip to content

Commit 0827777

Browse files
committed
Merge remote-tracking branch 'upstream/develop' into develop
2 parents 4be9ec2 + c0e1d71 commit 0827777

13 files changed

Lines changed: 1474 additions & 9 deletions

File tree

Dockerfile

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,6 @@ RUN ${RETRY} apt -y update -qq > /dev/null \
7171
make \
7272
openjdk-17-jdk \
7373
patch \
74-
patchelf \
7574
pkg-config \
7675
python3 \
7776
python3-dev \

doc/source/quickstart.rst

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,6 @@ the following command (re-adapted from the `Dockerfile` we use to perform CI bui
8686
make \
8787
openjdk-17-jdk \
8888
patch \
89-
patchelf \
9089
pkg-config \
9190
python3 \
9291
python3-dev \

pythonforandroid/recipe.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1311,7 +1311,7 @@ def build_arch(self, arch):
13111311
return
13121312

13131313
self.install_hostpython_prerequisites(
1314-
packages=["build[virtualenv]", "pip", "setuptools"] + self.hostpython_prerequisites
1314+
packages=["build[virtualenv]", "pip", "setuptools", "patchelf"] + self.hostpython_prerequisites
13151315
)
13161316
self.patch_shebangs(self._host_recipe.site_bin, self.real_hostpython_location)
13171317

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,15 @@
1-
from pythonforandroid.recipe import CppCompiledComponentsPythonRecipe
1+
from pythonforandroid.recipe import PyProjectRecipe
22

33

4-
class MaterialyoucolorRecipe(CppCompiledComponentsPythonRecipe):
4+
class MaterialyoucolorRecipe(PyProjectRecipe):
55
stl_lib_name = "c++_shared"
6-
version = "2.0.9"
6+
version = "2.0.10"
77
url = "https://github.com/T-Dynamos/materialyoucolor-python/releases/download/v{version}/materialyoucolor-{version}.tar.gz"
8-
depends = ["setuptools"]
8+
9+
def get_recipe_env(self, arch, **kwargs):
10+
env = super().get_recipe_env(arch, **kwargs)
11+
env['LDCXXSHARED'] = env['CXX'] + ' -shared'
12+
return env
913

1014

1115
recipe = MaterialyoucolorRecipe()

pythonforandroid/recipes/pydantic-core/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33

44
class PydanticcoreRecipe(RustCompiledComponentsRecipe):
5-
version = "2.16.1"
5+
version = "2.41.4"
66
url = "https://github.com/pydantic/pydantic-core/archive/refs/tags/v{version}.tar.gz"
77
site_packages_name = "pydantic_core"
88

tests/test_bdistapk.py

Lines changed: 200 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,200 @@
1+
import sys
2+
from unittest import mock
3+
from setuptools.dist import Distribution
4+
5+
from pythonforandroid.bdistapk import (
6+
argv_contains,
7+
BdistAPK,
8+
BdistAAR,
9+
BdistAAB,
10+
)
11+
12+
13+
class TestArgvContains:
14+
"""Test argv_contains helper function."""
15+
16+
def test_argv_contains_present(self):
17+
"""Test argv_contains returns True when argument is present."""
18+
with mock.patch.object(sys, 'argv', ['prog', '--name=test', '--version=1.0']):
19+
assert argv_contains('--name')
20+
assert argv_contains('--version')
21+
22+
def test_argv_contains_partial_match(self):
23+
"""Test argv_contains returns True for partial matches."""
24+
with mock.patch.object(sys, 'argv', ['prog', '--name=test']):
25+
assert argv_contains('--name')
26+
assert argv_contains('--nam')
27+
28+
def test_argv_contains_not_present(self):
29+
"""Test argv_contains returns False when argument is not present."""
30+
with mock.patch.object(sys, 'argv', ['prog', '--name=test']):
31+
assert not argv_contains('--package')
32+
assert not argv_contains('--arch')
33+
34+
35+
class TestBdist:
36+
"""Test Bdist base class."""
37+
38+
def setup_method(self):
39+
"""Set up test fixtures."""
40+
self.distribution = Distribution({
41+
'name': 'TestApp',
42+
'version': '1.0.0',
43+
})
44+
self.distribution.package_data = {'testapp': ['*.py', '*.kv']}
45+
46+
@mock.patch('pythonforandroid.bdistapk.ensure_dir')
47+
@mock.patch('pythonforandroid.bdistapk.rmdir')
48+
def test_initialize_options(self, mock_rmdir, mock_ensure_dir):
49+
"""Test initialize_options sets attributes from user_options."""
50+
bdist = BdistAPK(self.distribution)
51+
bdist.user_options = [('name=', None, None), ('version=', None, None)]
52+
53+
bdist.initialize_options()
54+
55+
assert hasattr(bdist, 'name')
56+
assert hasattr(bdist, 'version')
57+
58+
@mock.patch('pythonforandroid.bdistapk.argv_contains')
59+
@mock.patch('pythonforandroid.bdistapk.ensure_dir')
60+
@mock.patch('pythonforandroid.bdistapk.rmdir')
61+
def test_finalize_options_injects_defaults(
62+
self, mock_rmdir, mock_ensure_dir, mock_argv_contains
63+
):
64+
"""Test finalize_options injects default name, package, version, arch."""
65+
mock_argv_contains.return_value = False
66+
67+
with mock.patch.object(sys, 'argv', ['setup.py', 'apk']):
68+
bdist = BdistAPK(self.distribution)
69+
bdist.finalize_options()
70+
71+
# Check that defaults were added to sys.argv
72+
argv_str = ' '.join(sys.argv)
73+
assert '--name=' in argv_str or any('--name' in arg for arg in sys.argv)
74+
75+
@mock.patch('pythonforandroid.bdistapk.argv_contains')
76+
@mock.patch('pythonforandroid.bdistapk.ensure_dir')
77+
@mock.patch('pythonforandroid.bdistapk.rmdir')
78+
def test_finalize_options_permissions_handling(
79+
self, mock_rmdir, mock_ensure_dir, mock_argv_contains
80+
):
81+
"""Test finalize_options handles permissions list correctly."""
82+
mock_argv_contains.side_effect = lambda x: x != '--permissions'
83+
84+
# Set up permissions in the distribution command options
85+
self.distribution.command_options['apk'] = {
86+
'permissions': ('setup.py', ['INTERNET', 'CAMERA'])
87+
}
88+
89+
with mock.patch.object(sys, 'argv', ['setup.py', 'apk']):
90+
bdist = BdistAPK(self.distribution)
91+
bdist.package_type = 'apk'
92+
bdist.finalize_options()
93+
94+
# Check permissions were added
95+
assert any('--permission=INTERNET' in arg for arg in sys.argv)
96+
assert any('--permission=CAMERA' in arg for arg in sys.argv)
97+
98+
@mock.patch('pythonforandroid.entrypoints.main')
99+
@mock.patch('pythonforandroid.bdistapk.argv_contains')
100+
@mock.patch('pythonforandroid.bdistapk.ensure_dir')
101+
@mock.patch('pythonforandroid.bdistapk.rmdir')
102+
@mock.patch('pythonforandroid.bdistapk.copyfile')
103+
@mock.patch('pythonforandroid.bdistapk.glob')
104+
def test_run_calls_main(
105+
self, mock_glob, mock_copyfile, mock_rmdir, mock_ensure_dir,
106+
mock_argv_contains, mock_main
107+
):
108+
"""Test run() calls prepare_build_dir and then main()."""
109+
mock_glob.return_value = ['testapp/main.py']
110+
mock_argv_contains.return_value = False # Not using --launcher or --private
111+
112+
with mock.patch.object(sys, 'argv', ['setup.py', 'apk']):
113+
bdist = BdistAPK(self.distribution)
114+
bdist.arch = 'armeabi-v7a'
115+
bdist.run()
116+
117+
mock_rmdir.assert_called()
118+
mock_ensure_dir.assert_called()
119+
mock_main.assert_called_once()
120+
assert sys.argv[1] == 'apk'
121+
122+
@mock.patch('pythonforandroid.bdistapk.argv_contains')
123+
@mock.patch('pythonforandroid.bdistapk.ensure_dir')
124+
@mock.patch('pythonforandroid.bdistapk.rmdir')
125+
@mock.patch('pythonforandroid.bdistapk.copyfile')
126+
@mock.patch('pythonforandroid.bdistapk.glob')
127+
@mock.patch('builtins.exit', side_effect=SystemExit(1))
128+
def test_prepare_build_dir_no_main_py(
129+
self, mock_exit, mock_glob, mock_copyfile,
130+
mock_rmdir, mock_ensure_dir, mock_argv_contains
131+
):
132+
"""Test prepare_build_dir exits if no main.py found and not using launcher."""
133+
mock_glob.return_value = ['testapp/helper.py']
134+
mock_argv_contains.return_value = False # Not using --launcher
135+
136+
bdist = BdistAPK(self.distribution)
137+
bdist.arch = 'armeabi-v7a'
138+
139+
# Expect SystemExit to be raised
140+
try:
141+
bdist.prepare_build_dir()
142+
assert False, "Expected SystemExit to be raised"
143+
except SystemExit:
144+
pass
145+
146+
mock_exit.assert_called_once_with(1)
147+
148+
@mock.patch('pythonforandroid.bdistapk.argv_contains')
149+
@mock.patch('pythonforandroid.bdistapk.ensure_dir')
150+
@mock.patch('pythonforandroid.bdistapk.rmdir')
151+
@mock.patch('pythonforandroid.bdistapk.copyfile')
152+
@mock.patch('pythonforandroid.bdistapk.glob')
153+
def test_prepare_build_dir_with_main_py(
154+
self, mock_glob, mock_copyfile, mock_rmdir,
155+
mock_ensure_dir, mock_argv_contains
156+
):
157+
"""Test prepare_build_dir succeeds when main.py is found."""
158+
mock_glob.return_value = ['testapp/main.py', 'testapp/helper.py']
159+
# Return False for all argv_contains checks (no --launcher, no --private)
160+
mock_argv_contains.return_value = False
161+
162+
with mock.patch.object(sys, 'argv', ['setup.py', 'apk']):
163+
bdist = BdistAPK(self.distribution)
164+
bdist.arch = 'armeabi-v7a'
165+
bdist.prepare_build_dir()
166+
167+
# Should have copied files (glob might return duplicates)
168+
assert mock_copyfile.call_count >= 2
169+
# Should have added --private argument
170+
assert any('--private=' in arg for arg in sys.argv)
171+
172+
173+
class TestBdistSubclasses:
174+
"""Test BdistAPK, BdistAAR, BdistAAB subclasses."""
175+
176+
def setup_method(self):
177+
"""Set up test fixtures."""
178+
self.distribution = Distribution({
179+
'name': 'TestApp',
180+
'version': '1.0.0',
181+
})
182+
self.distribution.package_data = {}
183+
184+
def test_bdist_apk_package_type(self):
185+
"""Test BdistAPK has correct package_type."""
186+
bdist = BdistAPK(self.distribution)
187+
assert bdist.package_type == 'apk'
188+
assert bdist.description == 'Create an APK with python-for-android'
189+
190+
def test_bdist_aar_package_type(self):
191+
"""Test BdistAAR has correct package_type."""
192+
bdist = BdistAAR(self.distribution)
193+
assert bdist.package_type == 'aar'
194+
assert bdist.description == 'Create an AAR with python-for-android'
195+
196+
def test_bdist_aab_package_type(self):
197+
"""Test BdistAAB has correct package_type."""
198+
bdist = BdistAAB(self.distribution)
199+
assert bdist.package_type == 'aab'
200+
assert bdist.description == 'Create an AAB with python-for-android'

0 commit comments

Comments
 (0)