11# imports - standard imports
2+ import ast
23import os
34import pathlib
45import re
5- import sys
66import subprocess
7- from typing import List , Optional
7+ import sys
8+ import warnings
89from functools import lru_cache
10+ from typing import List , Optional
11+
12+ from bench .app import get_repo_dir
913
1014# imports - module imports
1115from 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
2024def is_version_upgrade (app = "frappe" , bench_path = "." , branch = None ):
@@ -36,8 +40,9 @@ def is_version_upgrade(app="frappe", bench_path=".", branch=None):
3640
3741def 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 )
179184def 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+
225243def 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