Skip to content

Commit cbdc7d7

Browse files
committed
Merge remote-tracking branch 'upstream/staging' into v5.x
* upstream/staging: fix(test): Install app from setup chore(bench): Add custom exception chore(bench): Throw if app name not found during install test(bench): Add test for app name feat(app): Parse app name from the ast Signed-off-by: Akhil Narang <me@akhilnarang.dev>
2 parents d60a2a4 + 2d40e69 commit cbdc7d7

File tree

3 files changed

+52
-8
lines changed

3 files changed

+52
-8
lines changed

bench/exceptions.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,3 +35,6 @@ class FeatureDoesNotExistError(CommandFailedError):
3535

3636
class VersionNotFound(Exception):
3737
pass
38+
39+
class AppInstallationError(CommandFailedError):
40+
pass

bench/tests/test_init.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,19 @@ def test_get_app_resolve_deps(self):
121121

122122
self.assertTrue(FRAPPE_APP in states)
123123

124+
def test_install_app_from_setup(self):
125+
app_name = "test-app"
126+
setup_file_contents = f"""
127+
from setuptools import setup, findpackages
128+
setup(name='{app_name}', version='0.1.0', packages=find_packages())
129+
"""
130+
131+
from bench.utils.app import get_app_name_from_setup
132+
133+
parsed_app_name = get_app_name_from_setup(setup_file_contents)
134+
135+
self.assertEqual(parsed_app_name, app_name)
136+
124137
def test_install_app(self):
125138
bench_name = "test-bench"
126139
site_name = "install-app.test"

bench/utils/app.py

Lines changed: 36 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,24 @@
11
# imports - standard imports
2+
import ast
23
import os
34
import pathlib
45
import re
5-
import sys
66
import subprocess
7-
from typing import List, Optional
7+
import sys
8+
import warnings
89
from functools import lru_cache
10+
from typing import List, Optional
11+
12+
from bench.app import get_repo_dir
913

1014
# imports - module imports
1115
from bench.exceptions import (
12-
InvalidRemoteException,
13-
InvalidBranchException,
16+
AppInstallationError,
1417
CommandFailedError,
18+
InvalidBranchException,
19+
InvalidRemoteException,
1520
VersionNotFound,
1621
)
17-
from bench.app import get_repo_dir
1822

1923

2024
def is_version_upgrade(app="frappe", bench_path=".", branch=None):
@@ -36,8 +40,9 @@ def is_version_upgrade(app="frappe", bench_path=".", branch=None):
3640

3741
def switch_branch(branch, apps=None, bench_path=".", upgrade=False, check_upgrade=True):
3842
import git
43+
3944
from bench.bench import Bench
40-
from bench.utils import log, exec_cmd
45+
from bench.utils import exec_cmd, log
4146
from bench.utils.bench import (
4247
build_assets,
4348
patch_sites,
@@ -177,9 +182,10 @@ def get_current_branch(app, bench_path="."):
177182

178183
@lru_cache(maxsize=5)
179184
def get_required_deps(org, name, branch, deps="hooks.py"):
180-
import requests
181185
import base64
182186

187+
import requests
188+
183189
git_api_url = f"https://api.github.com/repos/{org}/{name}/contents/{name}/{deps}"
184190
params = {"ref": branch or "develop"}
185191
res = requests.get(url=git_api_url, params=params).json()
@@ -222,6 +228,18 @@ def get_remote(app, bench_path="."):
222228
return contents.splitlines()[0].split()[0]
223229

224230

231+
def get_app_name_from_setup(contents: str) -> str | None:
232+
"""Parse the ast to find the app name in setup.py"""
233+
tree = ast.parse(contents)
234+
for node in tree.body:
235+
if isinstance(node, ast.Expr) and isinstance(node.value, ast.Call):
236+
call = node.value
237+
if getattr(call.func, "id", None) == "setup":
238+
for kwarg in call.keywords:
239+
if kwarg.arg == "name" and isinstance(kwarg.value, ast.Constant):
240+
return kwarg.value.value
241+
242+
225243
def get_app_name(bench_path: str, folder_name: str) -> str:
226244
"""Retrieves `name` attribute of app - equivalent to distribution name
227245
of python package. Fetches from pyproject.toml, setup.cfg or setup.py
@@ -247,7 +265,17 @@ def get_app_name(bench_path: str, folder_name: str) -> str:
247265
if not app_name:
248266
# retrieve app name from setup.py as fallback
249267
with open(setup_py_path, "rb") as f:
250-
app_name = re.search(r'name\s*=\s*[\'"](.*)[\'"]', f.read().decode("utf-8"))[1]
268+
warnings.warn(
269+
"setup.py is deprecated. Please migrate to pyproject.toml (PEP 621) for future releases.",
270+
DeprecationWarning,
271+
)
272+
app_name = get_app_name_from_setup(f.read().decode("utf-8"))
273+
274+
if not app_name:
275+
raise AppInstallationError(
276+
"Could not determine the package name. Checked pyproject.toml, setup.cfg, and setup.py."
277+
)
278+
251279

252280
if app_name and folder_name != app_name:
253281
os.rename(os.path.join(apps_path, folder_name), os.path.join(apps_path, app_name))

0 commit comments

Comments
 (0)