utils.py 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345
  1. # copyright (c) 2024 PaddlePaddle Authors. All Rights Reserve.
  2. #
  3. # Licensed under the Apache License, Version 2.0 (the "License");
  4. # you may not use this file except in compliance with the License.
  5. # You may obtain a copy of the License at
  6. #
  7. # http://www.apache.org/licenses/LICENSE-2.0
  8. #
  9. # Unless required by applicable law or agreed to in writing, software
  10. # distributed under the License is distributed on an "AS IS" BASIS,
  11. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. # See the License for the specific language governing permissions and
  13. # limitations under the License.
  14. import os
  15. import sys
  16. import json
  17. import platform
  18. import subprocess
  19. import contextlib
  20. from parsley import makeGrammar
  21. PLATFORM = platform.system()
  22. def _check_call(*args, **kwargs):
  23. return subprocess.check_call(*args, **kwargs)
  24. def _check_output(*args, **kwargs):
  25. return subprocess.check_output(*args, **kwargs)
  26. def _compare_version(version1, version2):
  27. import re
  28. def parse_version(version_str):
  29. version_pattern = re.compile(
  30. r'^(?P<major>\d+)\.(?P<minor>\d+)\.(?P<patch>\d+)(?:-(?P<pre_release>.*))?(?:\+(?P<build_metadata>.+))?$'
  31. )
  32. match = version_pattern.match(version_str)
  33. if not match:
  34. raise ValueError(f"Unexpected version string: {version_str}")
  35. return (
  36. int(match.group('major')), int(match.group('minor')),
  37. int(match.group('patch')), match.group('pre_release')
  38. )
  39. v1_infos = parse_version(version1)
  40. v2_infos = parse_version(version2)
  41. for v1_info, v2_info in zip(v1_infos, v2_infos):
  42. if v1_info is None and v2_info is None:
  43. continue
  44. if v1_info is None or (v2_info is not None and v1_info < v2_info):
  45. return -1
  46. if v2_info is None or (v1_info is not None and v1_info > v2_info):
  47. return 1
  48. return 0
  49. def check_installation_using_pip(pkg):
  50. """check_installation_using_pip"""
  51. out = _check_output(["pip", "list", "--format", "json"])
  52. out = out.rstrip()
  53. lst = json.loads(out)
  54. return any(ele["name"] == pkg for ele in lst)
  55. def uninstall_package_using_pip(pkg):
  56. """uninstall_package_using_pip"""
  57. return _check_call([sys.executable, "-m", "pip", "uninstall", "-y", pkg])
  58. def install_packages_using_pip(
  59. pkgs, editable=False, req_files=None, cons_files=None, no_deps=False, pip_flags=None
  60. ):
  61. """install_packages_using_pip"""
  62. args = [sys.executable, "-m", "pip", "install"]
  63. if editable:
  64. args.append("-e")
  65. if req_files is not None:
  66. for req_file in req_files:
  67. args.append("-r")
  68. args.append(req_file)
  69. if cons_files is not None:
  70. for cons_file in cons_files:
  71. args.append("-c")
  72. args.append(cons_file)
  73. if isinstance(pkgs, str):
  74. pkgs = [pkgs]
  75. args.extend(pkgs)
  76. if pip_flags is not None:
  77. args.extend(pip_flags)
  78. return _check_call(args)
  79. def install_external_deps(repo_name, repo_root):
  80. """install paddle repository custom dependencies"""
  81. import paddle
  82. from ..utils import logging
  83. paddle_version = paddle.__version__
  84. paddle_w_cuda = paddle.is_compiled_with_cuda()
  85. gcc_version = subprocess.check_output(["gcc", "--version"]).decode('utf-8').split()[2]
  86. if repo_name == 'PaddleDetection':
  87. if os.path.exists(os.path.join(repo_root, 'ppdet', 'ext_op')):
  88. """Install custom op for rotated object detection"""
  89. if _compare_version(paddle_version, '2.0.1') >= 0 and paddle_w_cuda and _compare_version(gcc_version, '8.2.0') >= 0:
  90. with switch_working_dir(os.path.join(repo_root, 'ppdet', 'ext_op')):
  91. args = [sys.executable, 'setup.py', 'install']
  92. _check_call(args)
  93. else:
  94. logging.warning(
  95. "The custom operators in PaddleDetection for Rotated Object Detection is only supported when using CUDA, GCC>=8.2.0 and Paddle>=2.0.1, \
  96. your environment does not meet these requirements, so we will skip the installation of custom operators under PaddleDetection/ppdet/ext_ops, \
  97. which means you can not train the Rotated Object Detection models."
  98. )
  99. def install_deps_using_pip():
  100. """install requirements"""
  101. current_file_path = os.path.dirname(os.path.abspath(__file__))
  102. deps_path = os.path.join(current_file_path, "requirements.txt")
  103. args = [sys.executable, "-m", "pip", "install", "-r", deps_path]
  104. return _check_call(args)
  105. def clone_repo_using_git(url, branch=None):
  106. """clone_repo_using_git"""
  107. args = ["git", "clone", "--depth", "1"]
  108. if isinstance(url, str):
  109. url = [url]
  110. args.extend(url)
  111. if branch is not None:
  112. args.extend(["-b", branch])
  113. return _check_call(args)
  114. def fetch_repo_using_git(branch, url, depth=1):
  115. """fetch_repo_using_git"""
  116. args = ["git", "fetch", url, branch, "--depth", str(depth)]
  117. _check_call(args)
  118. def reset_repo_using_git(pointer, hard=True):
  119. """reset_repo_using_git"""
  120. args = ["git", "reset", "--hard", pointer]
  121. return _check_call(args)
  122. def remove_repo_using_rm(name):
  123. """remove_repo_using_rm"""
  124. if os.path.exists(name):
  125. if PLATFORM == "Windows":
  126. return _check_call(["rmdir", "/S", "/Q", name], shell=True)
  127. else:
  128. return _check_call(["rm", "-rf", name])
  129. def build_wheel_using_pip(pkg, dst_dir="./", with_deps=False, pip_flags=None):
  130. """build_wheel_using_pip"""
  131. args = [sys.executable, "-m", "pip", "wheel", "--wheel-dir", dst_dir]
  132. if not with_deps:
  133. args.append("--no-deps")
  134. if pip_flags is not None:
  135. args.extend(pip_flags)
  136. args.append(pkg)
  137. return _check_call(args)
  138. @contextlib.contextmanager
  139. def mute():
  140. """mute"""
  141. with open(os.devnull, "w") as f:
  142. with contextlib.redirect_stdout(f), contextlib.redirect_stderr(f):
  143. yield
  144. @contextlib.contextmanager
  145. def switch_working_dir(new_wd):
  146. """switch_working_dir"""
  147. cwd = os.getcwd()
  148. os.chdir(new_wd)
  149. try:
  150. yield
  151. finally:
  152. os.chdir(cwd)
  153. def _build_dep_spec_pep508_grammar():
  154. # Refer to https://peps.python.org/pep-0508/
  155. grammar = """
  156. wsp = ' ' | '\t'
  157. version_cmp = wsp* <'<=' | '<' | '!=' | '==' | '>=' | '>' | '~=' | '==='>
  158. version = wsp* <(letterOrDigit | '-' | '_' | '.' | '*' | '+' | '!')+>
  159. version_one = version_cmp:op version:v wsp* -> (op, v)
  160. version_many = version_one:v1 (wsp* ',' version_one)*:v2 -> [v1] + v2
  161. versionspec = ('(' version_many:v ')' ->v) | version_many
  162. urlspec = '@' wsp* <uri_reference>
  163. marker_op = version_cmp | (wsp* 'in') | (wsp* 'not' wsp+ 'in')
  164. python_str_c = (wsp | letter | digit | '(' | ')' | '.' | '{' | '}' |
  165. '-' | '_' | '*' | '#' | ':' | ';' | ',' | '/' | '?' |
  166. '[' | ']' | '!' | '~' | '`' | '@' | '$' | '%' | '^' |
  167. '&' | '=' | '+' | '|' | '<' | '>' )
  168. dquote = '"'
  169. squote = '\\''
  170. comment = '#' <anything*>:s end -> s
  171. python_str = (squote <(python_str_c | dquote)*>:s squote |
  172. dquote <(python_str_c | squote)*>:s dquote) -> s
  173. env_var = ('python_version' | 'python_full_version' |
  174. 'os_name' | 'sys_platform' | 'platform_release' |
  175. 'platform_system' | 'platform_version' |
  176. 'platform_machine' | 'platform_python_implementation' |
  177. 'implementation_name' | 'implementation_version' |
  178. 'extra' # ONLY when defined by a containing layer
  179. )
  180. marker_var = wsp* (env_var | python_str)
  181. marker_expr = marker_var:l marker_op:o marker_var:r -> (o, l, r)
  182. | wsp* '(' marker:m wsp* ')' -> m
  183. marker_and = marker_expr:l wsp* 'and' marker_expr:r -> ('and', l, r)
  184. | marker_expr:m -> m
  185. marker_or = marker_and:l wsp* 'or' marker_and:r -> ('or', l, r)
  186. | marker_and:m -> m
  187. marker = marker_or
  188. quoted_marker = ';' wsp* marker
  189. identifier_end = letterOrDigit | (('-' | '_' | '.' )* letterOrDigit)
  190. identifier = <letterOrDigit identifier_end* >
  191. name = identifier
  192. extras_list = identifier:i (wsp* ',' wsp* identifier)*:ids -> [i] + ids
  193. extras = '[' wsp* extras_list?:e wsp* ']' -> e
  194. name_req = (name:n wsp* extras?:e wsp* versionspec?:v wsp* quoted_marker?:m
  195. -> (n, e or [], v or [], m))
  196. url_req = (name:n wsp* extras?:e wsp* urlspec:v (wsp+ | end) quoted_marker?:m
  197. -> (n, e or [], v, m))
  198. specification = wsp* (url_req | name_req):s wsp* comment? -> s
  199. # The result is a tuple - name, list-of-extras,
  200. # list-of-version-constraints-or-a-url, marker-ast or None
  201. uri_reference = <uri | relative_ref>
  202. uri = scheme ':' hier_part ('?' query )? ('#' fragment)?
  203. hier_part = ('//' authority path_abempty) | path_absolute | path_rootless | path_empty
  204. absolute_uri = scheme ':' hier_part ('?' query )?
  205. relative_ref = relative_part ('?' query )? ('#' fragment )?
  206. relative_part = '//' authority path_abempty | path_absolute | path_noscheme | path_empty
  207. scheme = letter (letter | digit | '+' | '-' | '.')*
  208. authority = (userinfo '@' )? host (':' port )?
  209. userinfo = (unreserved | pct_encoded | sub_delims | ':')*
  210. host = ip_literal | ipv4_address | reg_name
  211. port = digit*
  212. ip_literal = '[' (ipv6_address | ipvfuture) ']'
  213. ipvfuture = 'v' hexdig+ '.' (unreserved | sub_delims | ':')+
  214. ipv6_address = (
  215. (h16 ':'){6} ls32
  216. | '::' (h16 ':'){5} ls32
  217. | (h16 )? '::' (h16 ':'){4} ls32
  218. | ((h16 ':')? h16 )? '::' (h16 ':'){3} ls32
  219. | ((h16 ':'){0,2} h16 )? '::' (h16 ':'){2} ls32
  220. | ((h16 ':'){0,3} h16 )? '::' h16 ':' ls32
  221. | ((h16 ':'){0,4} h16 )? '::' ls32
  222. | ((h16 ':'){0,5} h16 )? '::' h16
  223. | ((h16 ':'){0,6} h16 )? '::' )
  224. h16 = hexdig{1,4}
  225. ls32 = (h16 ':' h16) | ipv4_address
  226. ipv4_address = dec_octet '.' dec_octet '.' dec_octet '.' dec_octet
  227. nz = ~'0' digit
  228. dec_octet = (
  229. digit # 0-9
  230. | nz digit # 10-99
  231. | '1' digit{2} # 100-199
  232. | '2' ('0' | '1' | '2' | '3' | '4') digit # 200-249
  233. | '25' ('0' | '1' | '2' | '3' | '4' | '5') )# %250-255
  234. reg_name = (unreserved | pct_encoded | sub_delims)*
  235. path = (
  236. path_abempty # begins with '/' or is empty
  237. | path_absolute # begins with '/' but not '//'
  238. | path_noscheme # begins with a non-colon segment
  239. | path_rootless # begins with a segment
  240. | path_empty ) # zero characters
  241. path_abempty = ('/' segment)*
  242. path_absolute = '/' (segment_nz ('/' segment)* )?
  243. path_noscheme = segment_nz_nc ('/' segment)*
  244. path_rootless = segment_nz ('/' segment)*
  245. path_empty = pchar{0}
  246. segment = pchar*
  247. segment_nz = pchar+
  248. segment_nz_nc = (unreserved | pct_encoded | sub_delims | '@')+
  249. # non-zero-length segment without any colon ':'
  250. pchar = unreserved | pct_encoded | sub_delims | ':' | '@'
  251. query = (pchar | '/' | '?')*
  252. fragment = (pchar | '/' | '?')*
  253. pct_encoded = '%' hexdig
  254. unreserved = letter | digit | '-' | '.' | '_' | '~'
  255. reserved = gen_delims | sub_delims
  256. gen_delims = ':' | '/' | '?' | '#' | '(' | ')?' | '@'
  257. sub_delims = '!' | '$' | '&' | '\\'' | '(' | ')' | '*' | '+' | ',' | ';' | '='
  258. hexdig = digit | 'a' | 'A' | 'b' | 'B' | 'c' | 'C' | 'd' | 'D' | 'e' | 'E' | 'f' | 'F'
  259. """
  260. compiled = makeGrammar(grammar, {})
  261. return compiled
  262. _pep508_grammar = None
  263. def to_dep_spec_pep508(s):
  264. """to_dep_spec_pep508"""
  265. global _pep508_grammar
  266. if _pep508_grammar is None:
  267. _pep508_grammar = _build_dep_spec_pep508_grammar()
  268. parsed = _pep508_grammar(s)
  269. return parsed.specification()
  270. def env_marker_ast2expr(marker_ast):
  271. """env_marker_ast2expr"""
  272. MARKER_VARS = (
  273. "python_version",
  274. "python_full_version",
  275. "os_name",
  276. "sys_platform",
  277. "platform_release",
  278. "platform_system",
  279. "platform_version",
  280. "platform_machine",
  281. "platform_python_implementation",
  282. "implementation_name",
  283. "implementation_version",
  284. "extra", # ONLY when defined by a containing layer
  285. )
  286. o, l, r = marker_ast
  287. if isinstance(l, tuple):
  288. l = env_marker_ast2expr(l)
  289. else:
  290. assert isinstance(l, str)
  291. if l not in MARKER_VARS:
  292. l = repr(l)
  293. if isinstance(r, tuple):
  294. r = env_marker_ast2expr(r)
  295. else:
  296. assert isinstance(r, str)
  297. if r not in MARKER_VARS:
  298. r = repr(r)
  299. return f"{l} {o} {r}"