api.py 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498
  1. # Copyright (C) 2012 Anaconda, Inc
  2. # SPDX-License-Identifier: BSD-3-Clause
  3. from .base.constants import DepsModifier as _DepsModifier
  4. from .base.constants import UpdateModifier as _UpdateModifier
  5. from .base.context import context
  6. from .common.constants import NULL
  7. from .core.package_cache_data import PackageCacheData as _PackageCacheData
  8. from .core.prefix_data import PrefixData as _PrefixData
  9. from .core.subdir_data import SubdirData as _SubdirData
  10. from .models.channel import Channel
  11. DepsModifier = _DepsModifier
  12. """Flags to enable alternate handling of dependencies."""
  13. UpdateModifier = _UpdateModifier
  14. """Flags to enable alternate handling for updates of existing packages in the environment."""
  15. class Solver:
  16. """
  17. **Beta** While in beta, expect both major and minor changes across minor releases.
  18. A high-level API to conda's solving logic. Three public methods are provided to access a
  19. solution in various forms.
  20. * :meth:`solve_final_state`
  21. * :meth:`solve_for_diff`
  22. * :meth:`solve_for_transaction`
  23. """
  24. def __init__(
  25. self, prefix, channels, subdirs=(), specs_to_add=(), specs_to_remove=()
  26. ):
  27. """
  28. **Beta**
  29. Args:
  30. prefix (str):
  31. The conda prefix / environment location for which the :class:`Solver`
  32. is being instantiated.
  33. channels (Sequence[:class:`Channel`]):
  34. A prioritized list of channels to use for the solution.
  35. subdirs (Sequence[str]):
  36. A prioritized list of subdirs to use for the solution.
  37. specs_to_add (set[:class:`MatchSpec`]):
  38. The set of package specs to add to the prefix.
  39. specs_to_remove (set[:class:`MatchSpec`]):
  40. The set of package specs to remove from the prefix.
  41. """
  42. solver_backend = context.plugin_manager.get_cached_solver_backend()
  43. self._internal = solver_backend(
  44. prefix, channels, subdirs, specs_to_add, specs_to_remove
  45. )
  46. def solve_final_state(
  47. self,
  48. update_modifier=NULL,
  49. deps_modifier=NULL,
  50. prune=NULL,
  51. ignore_pinned=NULL,
  52. force_remove=NULL,
  53. ):
  54. """
  55. **Beta** While in beta, expect both major and minor changes across minor releases.
  56. Gives the final, solved state of the environment.
  57. Args:
  58. deps_modifier (DepsModifier):
  59. An optional flag indicating special solver handling for dependencies. The
  60. default solver behavior is to be as conservative as possible with dependency
  61. updates (in the case the dependency already exists in the environment), while
  62. still ensuring all dependencies are satisfied. Options include
  63. * NO_DEPS
  64. * ONLY_DEPS
  65. * UPDATE_DEPS
  66. * UPDATE_DEPS_ONLY_DEPS
  67. * FREEZE_INSTALLED
  68. prune (bool):
  69. If ``True``, the solution will not contain packages that were
  70. previously brought into the environment as dependencies but are no longer
  71. required as dependencies and are not user-requested.
  72. ignore_pinned (bool):
  73. If ``True``, the solution will ignore pinned package configuration
  74. for the prefix.
  75. force_remove (bool):
  76. Forces removal of a package without removing packages that depend on it.
  77. Returns:
  78. tuple[PackageRef]:
  79. In sorted dependency order from roots to leaves, the package references for
  80. the solved state of the environment.
  81. """
  82. return self._internal.solve_final_state(
  83. update_modifier, deps_modifier, prune, ignore_pinned, force_remove
  84. )
  85. def solve_for_diff(
  86. self,
  87. update_modifier=NULL,
  88. deps_modifier=NULL,
  89. prune=NULL,
  90. ignore_pinned=NULL,
  91. force_remove=NULL,
  92. force_reinstall=False,
  93. ):
  94. """
  95. **Beta** While in beta, expect both major and minor changes across minor releases.
  96. Gives the package references to remove from an environment, followed by
  97. the package references to add to an environment.
  98. Args:
  99. deps_modifier (DepsModifier):
  100. See :meth:`solve_final_state`.
  101. prune (bool):
  102. See :meth:`solve_final_state`.
  103. ignore_pinned (bool):
  104. See :meth:`solve_final_state`.
  105. force_remove (bool):
  106. See :meth:`solve_final_state`.
  107. force_reinstall (bool):
  108. For requested specs_to_add that are already satisfied in the environment,
  109. instructs the solver to remove the package and spec from the environment,
  110. and then add it back--possibly with the exact package instance modified,
  111. depending on the spec exactness.
  112. Returns:
  113. tuple[PackageRef], tuple[PackageRef]:
  114. A two-tuple of PackageRef sequences. The first is the group of packages to
  115. remove from the environment, in sorted dependency order from leaves to roots.
  116. The second is the group of packages to add to the environment, in sorted
  117. dependency order from roots to leaves.
  118. """
  119. return self._internal.solve_for_diff(
  120. update_modifier,
  121. deps_modifier,
  122. prune,
  123. ignore_pinned,
  124. force_remove,
  125. force_reinstall,
  126. )
  127. def solve_for_transaction(
  128. self,
  129. update_modifier=NULL,
  130. deps_modifier=NULL,
  131. prune=NULL,
  132. ignore_pinned=NULL,
  133. force_remove=NULL,
  134. force_reinstall=False,
  135. ):
  136. """
  137. **Beta** While in beta, expect both major and minor changes across minor releases.
  138. Gives an UnlinkLinkTransaction instance that can be used to execute the solution
  139. on an environment.
  140. Args:
  141. deps_modifier (DepsModifier):
  142. See :meth:`solve_final_state`.
  143. prune (bool):
  144. See :meth:`solve_final_state`.
  145. ignore_pinned (bool):
  146. See :meth:`solve_final_state`.
  147. force_remove (bool):
  148. See :meth:`solve_final_state`.
  149. force_reinstall (bool):
  150. See :meth:`solve_for_diff`.
  151. Returns:
  152. UnlinkLinkTransaction:
  153. """
  154. return self._internal.solve_for_transaction(
  155. update_modifier,
  156. deps_modifier,
  157. prune,
  158. ignore_pinned,
  159. force_remove,
  160. force_reinstall,
  161. )
  162. class SubdirData:
  163. """
  164. **Beta** While in beta, expect both major and minor changes across minor releases.
  165. High-level management and usage of repodata.json for subdirs.
  166. """
  167. def __init__(self, channel):
  168. """
  169. **Beta** While in beta, expect both major and minor changes across minor releases.
  170. Args:
  171. channel (str or Channel):
  172. The target subdir for the instance. Must either be a url that includes a subdir
  173. or a :obj:`Channel` that includes a subdir. e.g.:
  174. * 'https://repo.anaconda.com/pkgs/main/linux-64'
  175. * Channel('https://repo.anaconda.com/pkgs/main/linux-64')
  176. * Channel('conda-forge/osx-64')
  177. """
  178. channel = Channel(channel)
  179. assert channel.subdir
  180. self._internal = _SubdirData(channel)
  181. def query(self, package_ref_or_match_spec):
  182. """
  183. **Beta** While in beta, expect both major and minor changes across minor releases.
  184. Run a query against this specific instance of repodata.
  185. Args:
  186. package_ref_or_match_spec (PackageRef or MatchSpec or str):
  187. Either an exact :obj:`PackageRef` to match against, or a :obj:`MatchSpec`
  188. query object. A :obj:`str` will be turned into a :obj:`MatchSpec` automatically.
  189. Returns:
  190. tuple[PackageRecord]
  191. """
  192. return tuple(self._internal.query(package_ref_or_match_spec))
  193. @staticmethod
  194. def query_all(package_ref_or_match_spec, channels=None, subdirs=None):
  195. """
  196. **Beta** While in beta, expect both major and minor changes across minor releases.
  197. Run a query against all repodata instances in channel/subdir matrix.
  198. Args:
  199. package_ref_or_match_spec (PackageRef or MatchSpec or str):
  200. Either an exact :obj:`PackageRef` to match against, or a :obj:`MatchSpec`
  201. query object. A :obj:`str` will be turned into a :obj:`MatchSpec` automatically.
  202. channels (Iterable[Channel or str] or None):
  203. An iterable of urls for channels or :obj:`Channel` objects. If None, will fall
  204. back to context.channels.
  205. subdirs (Iterable[str] or None):
  206. If None, will fall back to context.subdirs.
  207. Returns:
  208. tuple[PackageRecord]
  209. """
  210. return tuple(
  211. _SubdirData.query_all(package_ref_or_match_spec, channels, subdirs)
  212. )
  213. def iter_records(self):
  214. """
  215. **Beta** While in beta, expect both major and minor changes across minor releases.
  216. Returns:
  217. Iterable[PackageRecord]: A generator over all records contained in the repodata.json
  218. instance. Warning: this is a generator that is exhausted on first use.
  219. """
  220. return self._internal.iter_records()
  221. def reload(self):
  222. """
  223. **Beta** While in beta, expect both major and minor changes across minor releases.
  224. Update the instance with new information. Backing information (i.e. repodata.json)
  225. is lazily downloaded/loaded on first use by the other methods of this class. You
  226. should only use this method if you are *sure* you have outdated data.
  227. Returns:
  228. SubdirData
  229. """
  230. self._internal = self._internal.reload()
  231. return self
  232. class PackageCacheData:
  233. """
  234. **Beta** While in beta, expect both major and minor changes across minor releases.
  235. High-level management and usage of package caches.
  236. """
  237. def __init__(self, pkgs_dir):
  238. """
  239. **Beta** While in beta, expect both major and minor changes across minor releases.
  240. Args:
  241. pkgs_dir (str):
  242. """
  243. self._internal = _PackageCacheData(pkgs_dir)
  244. def get(self, package_ref, default=NULL):
  245. """
  246. **Beta** While in beta, expect both major and minor changes across minor releases.
  247. Args:
  248. package_ref (PackageRef):
  249. A :obj:`PackageRef` instance representing the key for the
  250. :obj:`PackageCacheRecord` being sought.
  251. default: The default value to return if the record does not exist. If not
  252. specified and no record exists, :exc:`KeyError` is raised.
  253. Returns:
  254. PackageCacheRecord
  255. """
  256. return self._internal.get(package_ref, default)
  257. def query(self, package_ref_or_match_spec):
  258. """
  259. **Beta** While in beta, expect both major and minor changes across minor releases.
  260. Run a query against this specific package cache instance.
  261. Args:
  262. package_ref_or_match_spec (PackageRef or MatchSpec or str):
  263. Either an exact :obj:`PackageRef` to match against, or a :obj:`MatchSpec`
  264. query object. A :obj:`str` will be turned into a :obj:`MatchSpec` automatically.
  265. Returns:
  266. tuple[PackageCacheRecord]
  267. """
  268. return tuple(self._internal.query(package_ref_or_match_spec))
  269. @staticmethod
  270. def query_all(package_ref_or_match_spec, pkgs_dirs=None):
  271. """
  272. **Beta** While in beta, expect both major and minor changes across minor releases.
  273. Run a query against all package caches.
  274. Args:
  275. package_ref_or_match_spec (PackageRef or MatchSpec or str):
  276. Either an exact :obj:`PackageRef` to match against, or a :obj:`MatchSpec`
  277. query object. A :obj:`str` will be turned into a :obj:`MatchSpec` automatically.
  278. pkgs_dirs (Iterable[str] or None):
  279. If None, will fall back to context.pkgs_dirs.
  280. Returns:
  281. tuple[PackageCacheRecord]
  282. """
  283. return tuple(_PackageCacheData.query_all(package_ref_or_match_spec, pkgs_dirs))
  284. def iter_records(self):
  285. """
  286. **Beta** While in beta, expect both major and minor changes across minor releases.
  287. Returns:
  288. Iterable[PackageCacheRecord]: A generator over all records contained in the package
  289. cache instance. Warning: this is a generator that is exhausted on first use.
  290. """
  291. return self._internal.iter_records()
  292. @property
  293. def is_writable(self):
  294. """
  295. **Beta** While in beta, expect both major and minor changes across minor releases.
  296. Indicates if the package cache location is writable or read-only.
  297. Returns:
  298. bool
  299. """
  300. return self._internal.is_writable
  301. @staticmethod
  302. def first_writable(pkgs_dirs=None):
  303. """
  304. **Beta** While in beta, expect both major and minor changes across minor releases.
  305. Get an instance object for the first writable package cache.
  306. Args:
  307. pkgs_dirs (Iterable[str]):
  308. If None, will fall back to context.pkgs_dirs.
  309. Returns:
  310. PackageCacheData:
  311. An instance for the first writable package cache.
  312. """
  313. return PackageCacheData(_PackageCacheData.first_writable(pkgs_dirs).pkgs_dir)
  314. def reload(self):
  315. """
  316. **Beta** While in beta, expect both major and minor changes across minor releases.
  317. Update the instance with new information. Backing information (i.e. contents of
  318. the pkgs_dir) is lazily loaded on first use by the other methods of this class. You
  319. should only use this method if you are *sure* you have outdated data.
  320. Returns:
  321. PackageCacheData
  322. """
  323. self._internal = self._internal.reload()
  324. return self
  325. class PrefixData:
  326. """
  327. **Beta** While in beta, expect both major and minor changes across minor releases.
  328. High-level management and usage of conda environment prefixes.
  329. """
  330. def __init__(self, prefix_path):
  331. """
  332. **Beta** While in beta, expect both major and minor changes across minor releases.
  333. Args:
  334. prefix_path (str):
  335. """
  336. self._internal = _PrefixData(prefix_path)
  337. def get(self, package_ref, default=NULL):
  338. """
  339. **Beta** While in beta, expect both major and minor changes across minor releases.
  340. Args:
  341. package_ref (PackageRef):
  342. A :obj:`PackageRef` instance representing the key for the
  343. :obj:`PrefixRecord` being sought.
  344. default: The default value to return if the record does not exist. If not
  345. specified and no record exists, :exc:`KeyError` is raised.
  346. Returns:
  347. PrefixRecord
  348. """
  349. return self._internal.get(package_ref.name, default)
  350. def query(self, package_ref_or_match_spec):
  351. """
  352. **Beta** While in beta, expect both major and minor changes across minor releases.
  353. Run a query against this specific prefix instance.
  354. Args:
  355. package_ref_or_match_spec (PackageRef or MatchSpec or str):
  356. Either an exact :obj:`PackageRef` to match against, or a :obj:`MatchSpec`
  357. query object. A :obj:`str` will be turned into a :obj:`MatchSpec` automatically.
  358. Returns:
  359. tuple[PrefixRecord]
  360. """
  361. return tuple(self._internal.query(package_ref_or_match_spec))
  362. def iter_records(self):
  363. """
  364. **Beta** While in beta, expect both major and minor changes across minor releases.
  365. Returns:
  366. Iterable[PrefixRecord]: A generator over all records contained in the prefix.
  367. Warning: this is a generator that is exhausted on first use.
  368. """
  369. return self._internal.iter_records()
  370. @property
  371. def is_writable(self):
  372. """
  373. **Beta** While in beta, expect both major and minor changes across minor releases.
  374. Indicates if the prefix is writable or read-only.
  375. Returns:
  376. bool or None:
  377. True if the prefix is writable. False if read-only. None if the prefix
  378. does not exist as a conda environment.
  379. """
  380. return self._internal.is_writable
  381. def reload(self):
  382. """
  383. **Beta** While in beta, expect both major and minor changes across minor releases.
  384. Update the instance with new information. Backing information (i.e. contents of
  385. the conda-meta directory) is lazily loaded on first use by the other methods of this
  386. class. You should only use this method if you are *sure* you have outdated data.
  387. Returns:
  388. PrefixData
  389. """
  390. self._internal = self._internal.reload()
  391. return self