A place to cache linked articles (think custom and personal wayback machine)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

index.html 66KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419
  1. <!doctype html><!-- This is a valid HTML5 document. -->
  2. <!-- Screen readers, SEO, extensions and so on. -->
  3. <html lang="en">
  4. <!-- Has to be within the first 1024 bytes, hence before the `title` element
  5. See: https://www.w3.org/TR/2012/CR-html5-20121217/document-metadata.html#charset -->
  6. <meta charset="utf-8">
  7. <!-- Why no `X-UA-Compatible` meta: https://stackoverflow.com/a/6771584 -->
  8. <!-- The viewport meta is quite crowded and we are responsible for that.
  9. See: https://codepen.io/tigt/post/meta-viewport-for-2015 -->
  10. <meta name="viewport" content="width=device-width,initial-scale=1">
  11. <!-- Required to make a valid HTML5 document. -->
  12. <title>uv: Python packaging in Rust (archive) — David Larlet</title>
  13. <meta name="description" content="Publication mise en cache pour en conserver une trace.">
  14. <!-- That good ol' feed, subscribe :). -->
  15. <link rel="alternate" type="application/atom+xml" title="Feed" href="/david/log/">
  16. <!-- Generated from https://realfavicongenerator.net/ such a mess. -->
  17. <link rel="apple-touch-icon" sizes="180x180" href="/static/david/icons2/apple-touch-icon.png">
  18. <link rel="icon" type="image/png" sizes="32x32" href="/static/david/icons2/favicon-32x32.png">
  19. <link rel="icon" type="image/png" sizes="16x16" href="/static/david/icons2/favicon-16x16.png">
  20. <link rel="manifest" href="/static/david/icons2/site.webmanifest">
  21. <link rel="mask-icon" href="/static/david/icons2/safari-pinned-tab.svg" color="#07486c">
  22. <link rel="shortcut icon" href="/static/david/icons2/favicon.ico">
  23. <meta name="msapplication-TileColor" content="#f7f7f7">
  24. <meta name="msapplication-config" content="/static/david/icons2/browserconfig.xml">
  25. <meta name="theme-color" content="#f7f7f7" media="(prefers-color-scheme: light)">
  26. <meta name="theme-color" content="#272727" media="(prefers-color-scheme: dark)">
  27. <!-- Is that even respected? Retrospectively? What a shAItshow…
  28. https://neil-clarke.com/block-the-bots-that-feed-ai-models-by-scraping-your-website/ -->
  29. <meta name="robots" content="noai, noimageai">
  30. <!-- Documented, feel free to shoot an email. -->
  31. <link rel="stylesheet" href="/static/david/css/style_2021-01-20.css">
  32. <!-- See https://www.zachleat.com/web/comprehensive-webfonts/ for the trade-off. -->
  33. <link rel="preload" href="/static/david/css/fonts/triplicate_t4_poly_regular.woff2" as="font" type="font/woff2" media="(prefers-color-scheme: light), (prefers-color-scheme: no-preference)" crossorigin>
  34. <link rel="preload" href="/static/david/css/fonts/triplicate_t4_poly_bold.woff2" as="font" type="font/woff2" media="(prefers-color-scheme: light), (prefers-color-scheme: no-preference)" crossorigin>
  35. <link rel="preload" href="/static/david/css/fonts/triplicate_t4_poly_italic.woff2" as="font" type="font/woff2" media="(prefers-color-scheme: light), (prefers-color-scheme: no-preference)" crossorigin>
  36. <link rel="preload" href="/static/david/css/fonts/triplicate_t3_regular.woff2" as="font" type="font/woff2" media="(prefers-color-scheme: dark)" crossorigin>
  37. <link rel="preload" href="/static/david/css/fonts/triplicate_t3_bold.woff2" as="font" type="font/woff2" media="(prefers-color-scheme: dark)" crossorigin>
  38. <link rel="preload" href="/static/david/css/fonts/triplicate_t3_italic.woff2" as="font" type="font/woff2" media="(prefers-color-scheme: dark)" crossorigin>
  39. <script>
  40. function toggleTheme(themeName) {
  41. document.documentElement.classList.toggle(
  42. 'forced-dark',
  43. themeName === 'dark'
  44. )
  45. document.documentElement.classList.toggle(
  46. 'forced-light',
  47. themeName === 'light'
  48. )
  49. }
  50. const selectedTheme = localStorage.getItem('theme')
  51. if (selectedTheme !== 'undefined') {
  52. toggleTheme(selectedTheme)
  53. }
  54. </script>
  55. <meta name="robots" content="noindex, nofollow">
  56. <meta content="origin-when-cross-origin" name="referrer">
  57. <!-- Canonical URL for SEO purposes -->
  58. <link rel="canonical" href="https://astral.sh/blog/uv">
  59. <body class="remarkdown h1-underline h2-underline h3-underline em-underscore hr-center ul-star pre-tick" data-instant-intensity="viewport-all">
  60. <article>
  61. <header>
  62. <h1>uv: Python packaging in Rust</h1>
  63. </header>
  64. <nav>
  65. <p class="center">
  66. <a href="/david/" title="Aller à l’accueil"><svg class="icon icon-home">
  67. <use xlink:href="/static/david/icons2/symbol-defs-2021-12.svg#icon-home"></use>
  68. </svg> Accueil</a> •
  69. <a href="https://astral.sh/blog/uv" title="Lien vers le contenu original">Source originale</a>
  70. <br>
  71. Mis en cache le 2024-02-17
  72. </p>
  73. </nav>
  74. <hr>
  75. <p><strong>TL;DR:</strong> <a href="https://github.com/astral-sh/uv">uv</a> is an <strong>extremely fast Python package
  76. installer and resolver</strong>, written in Rust, and designed as a drop-in replacement for <code>pip</code> and
  77. <code>pip-tools</code> workflows.</p>
  78. <p><a href="https://github.com/astral-sh/uv">uv</a> represents a milestone in our pursuit of a <a href="https://blog.rust-lang.org/2016/05/05/cargo-pillars.html#pillars-of-cargo">"Cargo for Python"</a>:
  79. a comprehensive Python project and package manager that's fast, reliable, and easy to use.</p>
  80. <p>As part of this release, we're also taking stewardship of <a href="https://github.com/mitsuhiko/rye">Rye</a>,
  81. an experimental Python packaging tool from <a href="https://github.com/mitsuhiko">Armin Ronacher</a>. We'll
  82. maintain <a href="https://github.com/mitsuhiko/rye">Rye</a> as we expand <a href="https://github.com/astral-sh/uv">uv</a> into a unified successor
  83. project, to fulfill our <a href="https://rye-up.com/philosophy/">shared vision</a> for Python packaging.</p>
  84. <hr>
  85. <p>At Astral, we build high-performance developer tools for the Python ecosystem. We're best known
  86. for <a href="https://github.com/astral-sh/ruff">Ruff</a>, an extremely fast
  87. Python <a href="https://notes.crmarsh.com/python-tooling-could-be-much-much-faster">linter</a>
  88. and <a href="https://astral.sh/blog/the-ruff-formatter">formatter</a>.</p>
  89. <p>Today, we're releasing the next tool in the Astral toolchain: <strong><a href="https://github.com/astral-sh/uv">uv</a>, an extremely fast Python
  90. package resolver and installer, written in Rust</strong>.</p>
  91. <div><div class="md:hidden"><svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 422 250"><g class="uv-warm-vertical-benchmark_svg__mark-group uv-warm-vertical-benchmark_svg__role-frame uv-warm-vertical-benchmark_svg__root" aria-roledescription="group mark container" fill="none" stroke-miterlimit="10"><path class="uv-warm-vertical-benchmark_svg__background" aria-hidden="true" d="M90 0Z"></path><g class="uv-warm-vertical-benchmark_svg__mark-group uv-warm-vertical-benchmark_svg__role-scope uv-warm-vertical-benchmark_svg__cell" aria-roledescription="group mark container"><path class="uv-warm-vertical-benchmark_svg__background" aria-hidden="true" d="M90 0h300v90H90Z"></path><g class="uv-warm-vertical-benchmark_svg__mark-group uv-warm-vertical-benchmark_svg__role-axis" aria-hidden="true"><path class="uv-warm-vertical-benchmark_svg__background" aria-hidden="true" d="M90.5 90.5Z" pointer-events="none"></path><g class="uv-warm-vertical-benchmark_svg__mark-rule uv-warm-vertical-benchmark_svg__role-axis-grid" pointer-events="none"><path stroke="rgba(127,127,127,0.25)" d="M90.5 90.5V.5M176.5 90.5V.5M261.5 90.5V.5M347.5 90.5V.5"></path></g></g><g class="uv-warm-vertical-benchmark_svg__mark-group uv-warm-vertical-benchmark_svg__role-axis" aria-roledescription="axis" aria-label="X-axis for a linear scale with values from 0.0 to 3.5"><path class="uv-warm-vertical-benchmark_svg__background" aria-hidden="true" d="M90.5 90.5Z" pointer-events="none"></path><g class="uv-warm-vertical-benchmark_svg__mark-rule uv-warm-vertical-benchmark_svg__role-axis-tick" pointer-events="none"><path stroke="rgba(127,127,127,0.25)" d="M347.5 90.5"></path></g><g class="uv-warm-vertical-benchmark_svg__mark-text uv-warm-vertical-benchmark_svg__role-axis-label" pointer-events="none"><text text-anchor="middle" transform="translate(90.5 105.5)" font-family="Roboto Mono,monospace" font-size="12" class="uv-warm-vertical-benchmark_svg__benchmarkLabel">0s
  92. </text><text text-anchor="middle" transform="translate(176.214 105.5)" font-family="Roboto Mono,monospace" font-size="12" class="uv-warm-vertical-benchmark_svg__benchmarkLabel">1s
  93. </text><text text-anchor="middle" transform="translate(261.929 105.5)" font-family="Roboto Mono,monospace" font-size="12" class="uv-warm-vertical-benchmark_svg__benchmarkLabel">2s
  94. </text><text text-anchor="middle" transform="translate(347.643 105.5)" font-family="Roboto Mono,monospace" font-size="12" class="uv-warm-vertical-benchmark_svg__benchmarkLabel">3s
  95. </text></g></g><g class="uv-warm-vertical-benchmark_svg__mark-group uv-warm-vertical-benchmark_svg__role-axis" aria-roledescription="axis" aria-label="Y-axis for a discrete scale with 4 values: uv, poetry, pip-compile, pdm"><path class="uv-warm-vertical-benchmark_svg__background" aria-hidden="true" d="M90.5.5Z" pointer-events="none"></path><g class="uv-warm-vertical-benchmark_svg__mark-text uv-warm-vertical-benchmark_svg__role-axis-label" pointer-events="none"><text text-anchor="end" transform="translate(80.5 15.25)" font-family="Roboto Mono,monospace" font-size="12" class="uv-warm-vertical-benchmark_svg__benchmarkLabel" font-weight="bold">uv
  96. </text><text text-anchor="end" transform="translate(80.5 37.75)" font-family="Roboto Mono,monospace" font-size="12" class="uv-warm-vertical-benchmark_svg__benchmarkLabel">poetry
  97. </text><text text-anchor="end" transform="translate(80.5 60.25)" font-family="Roboto Mono,monospace" font-size="12" class="uv-warm-vertical-benchmark_svg__benchmarkLabel">pip-compile
  98. </text><text text-anchor="end" transform="translate(80.5 82.75)" font-family="Roboto Mono,monospace" font-size="12" class="uv-warm-vertical-benchmark_svg__benchmarkLabel">pdm
  99. </text></g></g><g class="uv-warm-vertical-benchmark_svg__mark-rect uv-warm-vertical-benchmark_svg__role-mark uv-warm-vertical-benchmark_svg__child_layer_0_marks" aria-roledescription="rect mark container"><path aria-label="Sum of time: 0.0134756369786; tool: uv" aria-roledescription="bar" d="M90 4.75h1.155v13H90Z" class="uv-warm-vertical-benchmark_svg__benchmarkBar"></path><path aria-label="Sum of time: 0.60278702674; tool: poetry" aria-roledescription="bar" d="M90 27.25h51.667v13H90Z" class="uv-warm-vertical-benchmark_svg__benchmarkBar"></path><path aria-label="Sum of time: 1.55616658094; tool: pip-compile" aria-roledescription="bar" d="M90 49.75h133.386v13H90Z" class="uv-warm-vertical-benchmark_svg__benchmarkBar"></path><path aria-label="Sum of time: 3.37404433084; tool: pdm" aria-roledescription="bar" d="M90 72.25h289.204v13H90Z" class="uv-warm-vertical-benchmark_svg__benchmarkBar"></path></g><g class="uv-warm-vertical-benchmark_svg__mark-text uv-warm-vertical-benchmark_svg__role-mark uv-warm-vertical-benchmark_svg__child_layer_1_marks" aria-roledescription="text mark container"><text aria-label="Sum of time: 0.60278702674; tool: poetry; timeFormat: 0.60s" aria-roledescription="text mark" transform="translate(147.667 37.75)" font-family="Roboto Mono,monospace" font-size="12" class="uv-warm-vertical-benchmark_svg__benchmarkLabel">0.60s
  100. </text><text aria-label="Sum of time: 1.55616658094; tool: pip-compile; timeFormat: 1.56s" aria-roledescription="text mark" transform="translate(229.386 60.25)" font-family="Roboto Mono,monospace" font-size="12" class="uv-warm-vertical-benchmark_svg__benchmarkLabel">1.56s
  101. </text><text aria-label="Sum of time: 3.37404433084; tool: pdm; timeFormat: 3.37s" aria-roledescription="text mark" transform="translate(385.204 82.75)" font-family="Roboto Mono,monospace" font-size="12" class="uv-warm-vertical-benchmark_svg__benchmarkLabel">3.37s
  102. </text></g><g class="uv-warm-vertical-benchmark_svg__mark-text uv-warm-vertical-benchmark_svg__role-mark uv-warm-vertical-benchmark_svg__child_layer_2_marks" aria-roledescription="text mark container"><text aria-label="Sum of time: 0.0134756369786; tool: uv; timeFormat: 0.01s" aria-roledescription="text mark" transform="translate(97.155 15.25)" font-family="Roboto Mono,monospace" font-size="12" font-weight="bold" class="uv-warm-vertical-benchmark_svg__benchmarkLabel">0.01s
  103. </text></g><path class="uv-warm-vertical-benchmark_svg__background" aria-hidden="true" d="M90 143h300v90H90Z"></path><g class="uv-warm-vertical-benchmark_svg__mark-group uv-warm-vertical-benchmark_svg__role-axis" aria-hidden="true"><path class="uv-warm-vertical-benchmark_svg__background" aria-hidden="true" d="M90.5 233.5Z" pointer-events="none"></path><g class="uv-warm-vertical-benchmark_svg__mark-rule uv-warm-vertical-benchmark_svg__role-axis-grid" pointer-events="none"><path stroke="rgba(127,127,127,0.25)" d="M90.5 233.5v-90M210.5 233.5v-90M330.5 233.5v-90"></path></g></g><g class="uv-warm-vertical-benchmark_svg__mark-group uv-warm-vertical-benchmark_svg__role-axis" aria-roledescription="axis" aria-label="X-axis for a linear scale with values from 0 to 5"><path class="uv-warm-vertical-benchmark_svg__background" aria-hidden="true" d="M90.5 233.5Z" pointer-events="none"></path><g class="uv-warm-vertical-benchmark_svg__mark-rule uv-warm-vertical-benchmark_svg__role-axis-tick" pointer-events="none"><path stroke="rgba(127,127,127,0.25)" d="M330.5 233.5"></path></g><g class="uv-warm-vertical-benchmark_svg__mark-text uv-warm-vertical-benchmark_svg__role-axis-label" pointer-events="none"><text text-anchor="middle" transform="translate(90.5 248.5)" font-family="Roboto Mono,monospace" font-size="12" class="uv-warm-vertical-benchmark_svg__benchmarkLabel">0s
  104. </text><text text-anchor="middle" transform="translate(210.5 248.5)" font-family="Roboto Mono,monospace" font-size="12" class="uv-warm-vertical-benchmark_svg__benchmarkLabel">2s
  105. </text><text text-anchor="middle" transform="translate(330.5 248.5)" font-family="Roboto Mono,monospace" font-size="12" class="uv-warm-vertical-benchmark_svg__benchmarkLabel">4s
  106. </text></g></g><g class="uv-warm-vertical-benchmark_svg__mark-group uv-warm-vertical-benchmark_svg__role-axis" aria-roledescription="axis" aria-label="Y-axis for a discrete scale with 4 values: uv, poetry, pdm, pip-sync"><path class="uv-warm-vertical-benchmark_svg__background" aria-hidden="true" d="M90.5 143.5Z" pointer-events="none"></path><g class="uv-warm-vertical-benchmark_svg__mark-text uv-warm-vertical-benchmark_svg__role-axis-label" pointer-events="none"><text text-anchor="end" transform="translate(80.5 158.25)" font-family="Roboto Mono,monospace" font-size="12" class="uv-warm-vertical-benchmark_svg__benchmarkLabel" font-weight="bold">uv
  107. </text><text text-anchor="end" transform="translate(80.5 180.75)" font-family="Roboto Mono,monospace" font-size="12" class="uv-warm-vertical-benchmark_svg__benchmarkLabel">poetry
  108. </text><text text-anchor="end" transform="translate(80.5 203.25)" font-family="Roboto Mono,monospace" font-size="12" class="uv-warm-vertical-benchmark_svg__benchmarkLabel">pdm
  109. </text><text text-anchor="end" transform="translate(80.5 225.75)" font-family="Roboto Mono,monospace" font-size="12" class="uv-warm-vertical-benchmark_svg__benchmarkLabel">pip-sync
  110. </text></g></g><g class="uv-warm-vertical-benchmark_svg__mark-rect uv-warm-vertical-benchmark_svg__role-mark uv-warm-vertical-benchmark_svg__child_layer_0_marks" aria-roledescription="rect mark container"><path aria-label="Sum of time: 0.0576289908; tool: uv" aria-roledescription="bar" d="M90 147.75h3.458v13H90Z" class="uv-warm-vertical-benchmark_svg__benchmarkBar"></path><path aria-label="Sum of time: 0.9872183659; tool: poetry" aria-roledescription="bar" d="M90 170.25h59.233v13H90Z" class="uv-warm-vertical-benchmark_svg__benchmarkBar"></path><path aria-label="Sum of time: 1.8969612492; tool: pdm" aria-roledescription="bar" d="M90 192.75h113.818v13H90Z" class="uv-warm-vertical-benchmark_svg__benchmarkBar"></path><path aria-label="Sum of time: 4.6313483826; tool: pip-sync" aria-roledescription="bar" d="M90 215.25h277.88v13H90Z" class="uv-warm-vertical-benchmark_svg__benchmarkBar"></path></g><g class="uv-warm-vertical-benchmark_svg__mark-text uv-warm-vertical-benchmark_svg__role-mark uv-warm-vertical-benchmark_svg__child_layer_1_marks" aria-roledescription="text mark container"><text aria-label="Sum of time: 0.9872183659; tool: poetry; timeFormat: 0.99s" aria-roledescription="text mark" transform="translate(155.233 180.75)" font-family="Roboto Mono,monospace" font-size="12" class="uv-warm-vertical-benchmark_svg__benchmarkLabel">0.99s
  111. </text><text aria-label="Sum of time: 1.8969612492; tool: pdm; timeFormat: 1.90s" aria-roledescription="text mark" transform="translate(209.818 203.25)" font-family="Roboto Mono,monospace" font-size="12" class="uv-warm-vertical-benchmark_svg__benchmarkLabel">1.90s
  112. </text><text aria-label="Sum of time: 4.6313483826; tool: pip-sync; timeFormat: 4.63s" aria-roledescription="text mark" transform="translate(373.88 225.75)" font-family="Roboto Mono,monospace" font-size="12" class="uv-warm-vertical-benchmark_svg__benchmarkLabel">4.63s
  113. </text></g><g class="uv-warm-vertical-benchmark_svg__mark-text uv-warm-vertical-benchmark_svg__role-mark uv-warm-vertical-benchmark_svg__child_layer_2_marks" aria-roledescription="text mark container"><text aria-label="Sum of time: 0.0576289908; tool: uv; timeFormat: 0.06s" aria-roledescription="text mark" transform="translate(99.458 158.25)" font-family="Roboto Mono,monospace" font-size="12" font-weight="bold" class="uv-warm-vertical-benchmark_svg__benchmarkLabel">0.06s
  114. </text></g></g></g></svg></div><div class="hidden md:block"><div class="flex flex-col items-center text-flare md:flex-row md:justify-center"><div class="w-full md:w-[484px]"><svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 454 139"><g class="uv-resolve-warm-benchmark_svg__mark-group uv-resolve-warm-benchmark_svg__role-frame uv-resolve-warm-benchmark_svg__root" aria-roledescription="group mark container" fill="none" stroke-miterlimit="10"><path class="uv-resolve-warm-benchmark_svg__background" aria-hidden="true" d="M106 16h300v90H106Z"></path><g class="uv-resolve-warm-benchmark_svg__mark-group uv-resolve-warm-benchmark_svg__role-axis" aria-hidden="true"><path class="uv-resolve-warm-benchmark_svg__background" aria-hidden="true" d="M106.5 106.5Z" pointer-events="none"></path><g class="uv-resolve-warm-benchmark_svg__mark-rule uv-resolve-warm-benchmark_svg__role-axis-grid" pointer-events="none"><path stroke="rgba(127,127,127,0.25)" d="M106.5 106.5v-90M192.5 106.5v-90M277.5 106.5v-90M363.5 106.5v-90"></path></g></g><g class="uv-resolve-warm-benchmark_svg__mark-group uv-resolve-warm-benchmark_svg__role-axis" aria-roledescription="axis" aria-label="X-axis for a linear scale with values from 0.0 to 3.5"><path class="uv-resolve-warm-benchmark_svg__background" aria-hidden="true" d="M106.5 106.5Z" pointer-events="none"></path><g class="uv-resolve-warm-benchmark_svg__mark-rule uv-resolve-warm-benchmark_svg__role-axis-tick" pointer-events="none"><path stroke="rgba(127,127,127,0.25)" d="M363.5 106.5"></path></g><g class="uv-resolve-warm-benchmark_svg__mark-text uv-resolve-warm-benchmark_svg__role-axis-label" pointer-events="none"><text text-anchor="middle" transform="translate(106.5 121.5)" font-family="Roboto Mono,monospace" font-size="12" class="uv-resolve-warm-benchmark_svg__benchmarkLabel">0s
  115. </text><text text-anchor="middle" transform="translate(192.214 121.5)" font-family="Roboto Mono,monospace" font-size="12" class="uv-resolve-warm-benchmark_svg__benchmarkLabel">1s
  116. </text><text text-anchor="middle" transform="translate(277.929 121.5)" font-family="Roboto Mono,monospace" font-size="12" class="uv-resolve-warm-benchmark_svg__benchmarkLabel">2s
  117. </text><text text-anchor="middle" transform="translate(363.643 121.5)" font-family="Roboto Mono,monospace" font-size="12" class="uv-resolve-warm-benchmark_svg__benchmarkLabel">3s
  118. </text></g></g><g class="uv-resolve-warm-benchmark_svg__mark-group uv-resolve-warm-benchmark_svg__role-axis" aria-roledescription="axis" aria-label="Y-axis for a discrete scale with 4 values: uv, poetry, pip-compile, pdm"><path class="uv-resolve-warm-benchmark_svg__background" aria-hidden="true" d="M106.5 16.5Z" pointer-events="none"></path><g class="uv-resolve-warm-benchmark_svg__mark-text uv-resolve-warm-benchmark_svg__role-axis-label" pointer-events="none"><text text-anchor="end" transform="translate(96.5 31.25)" font-family="Roboto Mono,monospace" font-size="12" class="uv-resolve-warm-benchmark_svg__benchmarkLabel" font-weight="bold">uv
  119. </text><text text-anchor="end" transform="translate(96.5 53.75)" font-family="Roboto Mono,monospace" font-size="12" class="uv-resolve-warm-benchmark_svg__benchmarkLabel">poetry
  120. </text><text text-anchor="end" transform="translate(96.5 76.25)" font-family="Roboto Mono,monospace" font-size="12" class="uv-resolve-warm-benchmark_svg__benchmarkLabel">pip-compile
  121. </text><text text-anchor="end" transform="translate(96.5 98.75)" font-family="Roboto Mono,monospace" font-size="12" class="uv-resolve-warm-benchmark_svg__benchmarkLabel">pdm
  122. </text></g></g><g class="uv-resolve-warm-benchmark_svg__mark-rect uv-resolve-warm-benchmark_svg__role-mark uv-resolve-warm-benchmark_svg__layer_0_marks" aria-roledescription="rect mark container"><path aria-label="Sum of time: 0.0134756369786; tool: uv" aria-roledescription="bar" d="M106 20.75h1.155v13H106Z" class="uv-resolve-warm-benchmark_svg__benchmarkBar"></path><path aria-label="Sum of time: 0.60278702674; tool: poetry" aria-roledescription="bar" d="M106 43.25h51.667v13H106Z" class="uv-resolve-warm-benchmark_svg__benchmarkBar"></path><path aria-label="Sum of time: 1.55616658094; tool: pip-compile" aria-roledescription="bar" d="M106 65.75h133.386v13H106Z" class="uv-resolve-warm-benchmark_svg__benchmarkBar"></path><path aria-label="Sum of time: 3.37404433084; tool: pdm" aria-roledescription="bar" d="M106 88.25h289.204v13H106Z" class="uv-resolve-warm-benchmark_svg__benchmarkBar"></path></g><g class="uv-resolve-warm-benchmark_svg__mark-text uv-resolve-warm-benchmark_svg__role-mark uv-resolve-warm-benchmark_svg__layer_1_marks" aria-roledescription="text mark container"><text aria-label="Sum of time: 0.60278702674; tool: poetry; timeFormat: 0.60s" aria-roledescription="text mark" transform="translate(163.667 53.75)" font-family="Roboto Mono,monospace" font-size="12" class="uv-resolve-warm-benchmark_svg__benchmarkLabel">0.60s
  123. </text><text aria-label="Sum of time: 1.55616658094; tool: pip-compile; timeFormat: 1.56s" aria-roledescription="text mark" transform="translate(245.386 76.25)" font-family="Roboto Mono,monospace" font-size="12" class="uv-resolve-warm-benchmark_svg__benchmarkLabel">1.56s
  124. </text><text aria-label="Sum of time: 3.37404433084; tool: pdm; timeFormat: 3.37s" aria-roledescription="text mark" transform="translate(401.204 98.75)" font-family="Roboto Mono,monospace" font-size="12" class="uv-resolve-warm-benchmark_svg__benchmarkLabel">3.37s
  125. </text></g><g class="uv-resolve-warm-benchmark_svg__mark-text uv-resolve-warm-benchmark_svg__role-mark uv-resolve-warm-benchmark_svg__layer_2_marks" aria-roledescription="text mark container"><text aria-label="Sum of time: 0.0134756369786; tool: uv; timeFormat: 0.01s" aria-roledescription="text mark" transform="translate(113.155 31.25)" font-family="Roboto Mono,monospace" font-size="12" font-weight="bold" class="uv-resolve-warm-benchmark_svg__benchmarkLabel">0.01s
  126. </text></g></g></svg></div><div class="w-full md:w-[484px]"><svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 454 139"><g class="uv-install-warm-benchmark_svg__mark-group uv-install-warm-benchmark_svg__role-frame uv-install-warm-benchmark_svg__root" aria-roledescription="group mark container" fill="none" stroke-miterlimit="10"><path class="uv-install-warm-benchmark_svg__background" aria-hidden="true" d="M84 16h300v90H84Z"></path><g class="uv-install-warm-benchmark_svg__mark-group uv-install-warm-benchmark_svg__role-axis" aria-hidden="true"><path class="uv-install-warm-benchmark_svg__background" aria-hidden="true" d="M84.5 106.5Z" pointer-events="none"></path><g class="uv-install-warm-benchmark_svg__mark-rule uv-install-warm-benchmark_svg__role-axis-grid" pointer-events="none"><path stroke="rgba(127,127,127,0.25)" d="M84.5 106.5v-90M204.5 106.5v-90M324.5 106.5v-90"></path></g></g><g class="uv-install-warm-benchmark_svg__mark-group uv-install-warm-benchmark_svg__role-axis" aria-roledescription="axis" aria-label="X-axis for a linear scale with values from 0 to 5"><path class="uv-install-warm-benchmark_svg__background" aria-hidden="true" d="M84.5 106.5Z" pointer-events="none"></path><g class="uv-install-warm-benchmark_svg__mark-rule uv-install-warm-benchmark_svg__role-axis-tick" pointer-events="none"><path stroke="rgba(127,127,127,0.25)" d="M324.5 106.5"></path></g><g class="uv-install-warm-benchmark_svg__mark-text uv-install-warm-benchmark_svg__role-axis-label" pointer-events="none"><text text-anchor="middle" transform="translate(84.5 121.5)" font-family="Roboto Mono,monospace" font-size="12" class="uv-install-warm-benchmark_svg__benchmarkLabel">0s
  127. </text><text text-anchor="middle" transform="translate(204.5 121.5)" font-family="Roboto Mono,monospace" font-size="12" class="uv-install-warm-benchmark_svg__benchmarkLabel">2s
  128. </text><text text-anchor="middle" transform="translate(324.5 121.5)" font-family="Roboto Mono,monospace" font-size="12" class="uv-install-warm-benchmark_svg__benchmarkLabel">4s
  129. </text></g></g><g class="uv-install-warm-benchmark_svg__mark-group uv-install-warm-benchmark_svg__role-axis" aria-roledescription="axis" aria-label="Y-axis for a discrete scale with 4 values: uv, poetry, pdm, pip-sync"><path class="uv-install-warm-benchmark_svg__background" aria-hidden="true" d="M84.5 16.5Z" pointer-events="none"></path><g class="uv-install-warm-benchmark_svg__mark-text uv-install-warm-benchmark_svg__role-axis-label" pointer-events="none"><text text-anchor="end" transform="translate(74.5 31.25)" font-family="Roboto Mono,monospace" font-size="12" class="uv-install-warm-benchmark_svg__benchmarkLabel" font-weight="bold">uv
  130. </text><text text-anchor="end" transform="translate(74.5 53.75)" font-family="Roboto Mono,monospace" font-size="12" class="uv-install-warm-benchmark_svg__benchmarkLabel">poetry
  131. </text><text text-anchor="end" transform="translate(74.5 76.25)" font-family="Roboto Mono,monospace" font-size="12" class="uv-install-warm-benchmark_svg__benchmarkLabel">pdm
  132. </text><text text-anchor="end" transform="translate(74.5 98.75)" font-family="Roboto Mono,monospace" font-size="12" class="uv-install-warm-benchmark_svg__benchmarkLabel">pip-sync
  133. </text></g></g><g class="uv-install-warm-benchmark_svg__mark-rect uv-install-warm-benchmark_svg__role-mark uv-install-warm-benchmark_svg__layer_0_marks" aria-roledescription="rect mark container"><path aria-label="Sum of time: 0.0576289908; tool: uv" aria-roledescription="bar" d="M84 20.75h3.458v13H84Z" class="uv-install-warm-benchmark_svg__benchmarkBar"></path><path aria-label="Sum of time: 0.9872183659; tool: poetry" aria-roledescription="bar" d="M84 43.25h59.233v13H84Z" class="uv-install-warm-benchmark_svg__benchmarkBar"></path><path aria-label="Sum of time: 1.8969612492; tool: pdm" aria-roledescription="bar" d="M84 65.75h113.818v13H84Z" class="uv-install-warm-benchmark_svg__benchmarkBar"></path><path aria-label="Sum of time: 4.6313483826; tool: pip-sync" aria-roledescription="bar" d="M84 88.25h277.88v13H84Z" class="uv-install-warm-benchmark_svg__benchmarkBar"></path></g><g class="uv-install-warm-benchmark_svg__mark-text uv-install-warm-benchmark_svg__role-mark uv-install-warm-benchmark_svg__layer_1_marks" aria-roledescription="text mark container"><text aria-label="Sum of time: 0.9872183659; tool: poetry; timeFormat: 0.99s" aria-roledescription="text mark" transform="translate(149.233 53.75)" font-family="Roboto Mono,monospace" font-size="12" class="uv-install-warm-benchmark_svg__benchmarkLabel">0.99s
  134. </text><text aria-label="Sum of time: 1.8969612492; tool: pdm; timeFormat: 1.90s" aria-roledescription="text mark" transform="translate(203.818 76.25)" font-family="Roboto Mono,monospace" font-size="12" class="uv-install-warm-benchmark_svg__benchmarkLabel">1.90s
  135. </text><text aria-label="Sum of time: 4.6313483826; tool: pip-sync; timeFormat: 4.63s" aria-roledescription="text mark" transform="translate(367.88 98.75)" font-family="Roboto Mono,monospace" font-size="12" class="uv-install-warm-benchmark_svg__benchmarkLabel">4.63s
  136. </text></g><g class="uv-install-warm-benchmark_svg__mark-text uv-install-warm-benchmark_svg__role-mark uv-install-warm-benchmark_svg__layer_2_marks" aria-roledescription="text mark container"><text aria-label="Sum of time: 0.0576289908; tool: uv; timeFormat: 0.06s" aria-roledescription="text mark" transform="translate(93.458 31.25)" font-family="Roboto Mono,monospace" font-size="12" font-weight="bold" class="uv-install-warm-benchmark_svg__benchmarkLabel">0.06s
  137. </text></g></g></svg></div></div></div><div class="flex flex-row items-center"><p class="hidden text-sm md:block"><span class="opacity-75">Resolving (left) and installing (right) the <a class="cursor-pointer" target="_blank" rel="noreferrer" href="https://github.com/python-trio/trio">Trio</a> dependencies with a </span><a class="cursor-pointer select-none" aria-label="Toggle cache" tabindex="0" type="button">warm</a> <span class="opacity-75">cache, to simulate recreating a virtual environment or adding a dependency to an existing project (<a href="https://github.com/astral-sh/uv/blob/main/BENCHMARKS.md" target="_blank" rel="noreferrer">source</a>).</span></p><p class="text-sm md:hidden"><span class="opacity-75">Resolving (top) and installing (bottom) the <a class="cursor-pointer" target="_blank" rel="noreferrer" href="https://github.com/python-trio/trio">Trio</a> dependencies with a </span><a class="cursor-pointer select-none" aria-label="Toggle cache" tabindex="0" type="button">warm</a> <span class="opacity-75">cache, to simulate recreating a virtual environment or adding a dependency to an existing project (<a href="https://github.com/astral-sh/uv/blob/main/BENCHMARKS.md" target="_blank" rel="noreferrer">source</a>).</span></p></div></div>
  138. <p><a href="https://github.com/astral-sh/uv">uv</a> is designed as a drop-in replacement for <code>pip</code> and <code>pip-tools</code>,
  139. and is ready for production use today in projects built around those workflows.</p>
  140. <p>Like <a href="https://github.com/astral-sh/ruff">Ruff</a>, uv's implementation was grounded in our core
  141. product principles:</p>
  142. <ol>
  143. <li><strong>An obsessive focus on performance.</strong> In the above <a href="https://github.com/astral-sh/uv/blob/main/BENCHMARKS.md">benchmarks</a>,
  144. uv is <strong>8-10x faster</strong> than <code>pip</code> and <code>pip-tools</code> without caching, and <strong>80-115x faster</strong>
  145. when running with a warm cache (e.g., recreating a virtual environment or updating a dependency).
  146. uv uses a global module cache to avoid re-downloading and re-building dependencies, and
  147. leverages Copy-on-Write and hardlinks on supported filesystems to minimize disk space usage.</li>
  148. <li><strong>Optimized for adoption.</strong> While we have big aspirations for the future of Python packaging,
  149. uv's initial release is centered on supporting the <code>pip</code> and <code>pip-tools</code> APIs behind
  150. our <code>uv pip</code> interface, making it usable by existing projects with zero configuration.
  151. Similarly, uv can be used as "just" a resolver (<code>uv pip compile</code> to lock your
  152. dependencies), "just" a virtual environment creator (<code>uv venv</code>), "just" a package
  153. installer (<code>uv pip sync</code>), and so on. It's both unified and modular.</li>
  154. <li><strong>A simplified toolchain.</strong> uv ships as a single static binary capable of
  155. replacing <code>pip</code>, <code>pip-tools</code>, and <code>virtualenv</code>. uv has no direct Python dependency, so you
  156. can install it separately from Python itself, avoiding the need to manage <code>pip</code> installations
  157. across multiple Python versions (e.g., <code>pip</code> vs. <code>pip3</code> vs. <code>pip3.7</code>).</li>
  158. </ol>
  159. <p>While uv will evolve into a <strong>complete Python project and package manager</strong> (a <a href="https://blog.rust-lang.org/2016/05/05/cargo-pillars.html#pillars-of-cargo">"Cargo for Python"</a>),
  160. the narrower <code>pip-tools</code> scope allows us to solve the low-level problems involved in building such
  161. a tool (like package installation) while shipping something immediately useful with minimal barrier
  162. to adoption.</p>
  163. <p>You can install <a href="https://github.com/astral-sh/uv">uv</a> today via our standalone installers,
  164. or from <a href="https://pypi.org/project/uv/">PyPI</a>.</p>
  165. <p><a href="https://github.com/astral-sh/uv">uv</a> supports everything you'd expect from a modern Python
  166. packaging tool: editable installs, Git dependencies, URL dependencies, local dependencies,
  167. constraint files, source distributions, custom indexes, and more, all designed around drop-in
  168. compatibility with your existing tools.</p>
  169. <p><a href="https://github.com/astral-sh/uv">uv</a> supports <strong>Linux</strong>, <strong>Windows</strong>, and <strong>macOS</strong>, and
  170. has been tested at-scale against the public PyPI index.</p>
  171. <h3 class="hover:none group cursor-default"><span id="a-drop-in-compatible-api" class="invisible absolute mt-[-24px] block pt-[24px]"></span>A drop-in compatible API <a href="#a-drop-in-compatible-api" class="hidden group-hover:inline-block">#</a></h3>
  172. <p>This initial release centers on what we refer to as uv's <code>pip</code> API. It'll be familiar to those
  173. that have used <code>pip</code> and <code>pip-tools</code> in the past:</p>
  174. <ul>
  175. <li>Instead of <code>pip install</code>, run <code>uv pip install</code> to install Python dependencies from the command
  176. line, a requirements file, or a <code>pyproject.toml</code>.</li>
  177. <li>Instead of <code>pip-compile</code>, run <code>uv pip compile</code> to generate a locked <code>requirements.txt</code>.</li>
  178. <li>Instead of <code>pip-sync</code>, run <code>uv pip sync</code> to sync a virtual environment with a locked <code>requirements.txt</code>.</li>
  179. </ul>
  180. <p>By scoping these "lower-level" commands under <code>uv pip</code>, we retain space in the CLI for the more
  181. "opinionated" project management API we intend to ship in the future, which will look more like
  182. <a href="https://github.com/mitsuhiko/rye">Rye</a>, or <a href="https://github.com/rust-lang/cargo">Cargo</a>, or
  183. <a href="https://github.com/python-poetry/poetry">Poetry</a>. (Imagine <code>uv run</code>, <code>uv build</code>, and so on.)</p>
  184. <p>uv can also be used as a virtual environment manager via <code>uv venv</code>. It's about 80x
  185. faster than <code>python -m venv</code> and 7x faster than <code>virtualenv</code>, with no dependency on Python.</p>
  186. <div><div class="md:hidden"><svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 454 282"><g class="uv-venv-vertical-benchmark_svg__mark-group uv-venv-vertical-benchmark_svg__role-frame uv-venv-vertical-benchmark_svg__root" aria-roledescription="group mark container" fill="none" stroke-miterlimit="10"><path class="uv-venv-vertical-benchmark_svg__background" aria-hidden="true" d="M107 16Z"></path><g class="uv-venv-vertical-benchmark_svg__mark-group uv-venv-vertical-benchmark_svg__role-scope uv-venv-vertical-benchmark_svg__cell" aria-roledescription="group mark container"><path class="uv-venv-vertical-benchmark_svg__background" aria-hidden="true" d="M107 16h300v90H107Z"></path><g class="uv-venv-vertical-benchmark_svg__mark-group uv-venv-vertical-benchmark_svg__role-axis" aria-hidden="true"><path class="uv-venv-vertical-benchmark_svg__background" aria-hidden="true" d="M107.5 106.5Z" pointer-events="none"></path><g class="uv-venv-vertical-benchmark_svg__mark-rule uv-venv-vertical-benchmark_svg__role-axis-grid" pointer-events="none"><path stroke="rgba(127,127,127,0.25)" d="M107.5 106.5v-90M182.5 106.5v-90M257.5 106.5v-90M332.5 106.5v-90M407.5 106.5v-90"></path></g></g><g class="uv-venv-vertical-benchmark_svg__mark-group uv-venv-vertical-benchmark_svg__role-axis" aria-roledescription="axis" aria-label="X-axis for a linear scale with values from 0.00 to 0.08"><path class="uv-venv-vertical-benchmark_svg__background" aria-hidden="true" d="M107.5 106.5Z" pointer-events="none"></path><g class="uv-venv-vertical-benchmark_svg__mark-rule uv-venv-vertical-benchmark_svg__role-axis-tick" pointer-events="none"><path stroke="rgba(127,127,127,0.25)" d="M407.5 106.5"></path></g><g class="uv-venv-vertical-benchmark_svg__mark-text uv-venv-vertical-benchmark_svg__role-axis-label" pointer-events="none"><text text-anchor="middle" transform="translate(107.5 121.5)" font-family="Roboto Mono,monospace" font-size="12" class="uv-venv-vertical-benchmark_svg__benchmarkLabel">0s
  187. </text><text text-anchor="middle" transform="translate(182.5 121.5)" font-family="Roboto Mono,monospace" font-size="12" class="uv-venv-vertical-benchmark_svg__benchmarkLabel">0.02s
  188. </text><text text-anchor="middle" transform="translate(257.5 121.5)" font-family="Roboto Mono,monospace" font-size="12" class="uv-venv-vertical-benchmark_svg__benchmarkLabel">0.04s
  189. </text><text text-anchor="middle" transform="translate(332.5 121.5)" font-family="Roboto Mono,monospace" font-size="12" class="uv-venv-vertical-benchmark_svg__benchmarkLabel">0.06s
  190. </text><text text-anchor="middle" transform="translate(407.5 121.5)" font-family="Roboto Mono,monospace" font-size="12" class="uv-venv-vertical-benchmark_svg__benchmarkLabel">0.08s
  191. </text></g></g><g class="uv-venv-vertical-benchmark_svg__mark-rect uv-venv-vertical-benchmark_svg__role-mark uv-venv-vertical-benchmark_svg__child_layer_0_marks" aria-roledescription="rect mark container"><path aria-label="Sum of time: 0.0041; tool: uv" aria-roledescription="bar" d="M107 24.5h15.375v13H107Z" class="uv-venv-vertical-benchmark_svg__benchmarkBar"></path><path aria-label="Sum of time: 0.0744; tool: virtualenv" aria-roledescription="bar" d="M107 54.5h279v13H107Z" class="uv-venv-vertical-benchmark_svg__benchmarkBar"></path><path aria-label="Sum of time: 0.0241; tool: venv" aria-roledescription="bar" d="M107 84.5h90.375v13H107Z" class="uv-venv-vertical-benchmark_svg__benchmarkBar"></path></g><g class="uv-venv-vertical-benchmark_svg__mark-text uv-venv-vertical-benchmark_svg__role-mark uv-venv-vertical-benchmark_svg__child_layer_1_marks" aria-roledescription="text mark container"><text aria-label="Sum of time: 0.0744; tool: virtualenv; timeFormat: 74.4ms" aria-roledescription="text mark" transform="translate(392 65)" font-family="Roboto Mono,monospace" font-size="12" class="uv-venv-vertical-benchmark_svg__benchmarkLabel">74.4ms
  192. </text><text aria-label="Sum of time: 0.0241; tool: venv; timeFormat: 24.1ms" aria-roledescription="text mark" transform="translate(203.375 95)" font-family="Roboto Mono,monospace" font-size="12" class="uv-venv-vertical-benchmark_svg__benchmarkLabel">24.1ms
  193. </text></g><g class="uv-venv-vertical-benchmark_svg__mark-text uv-venv-vertical-benchmark_svg__role-mark uv-venv-vertical-benchmark_svg__child_layer_2_marks" aria-roledescription="text mark container"><text aria-label="Sum of time: 0.0041; tool: uv; timeFormat: 4.1ms" aria-roledescription="text mark" transform="translate(128.375 35)" font-family="Roboto Mono,monospace" font-size="12" font-weight="bold" class="uv-venv-vertical-benchmark_svg__benchmarkLabel">4.1ms
  194. </text></g><path class="uv-venv-vertical-benchmark_svg__background" aria-hidden="true" d="M107 159h300v90H107Z"></path><g class="uv-venv-vertical-benchmark_svg__mark-group uv-venv-vertical-benchmark_svg__role-axis" aria-hidden="true"><path class="uv-venv-vertical-benchmark_svg__background" aria-hidden="true" d="M107.5 249.5Z" pointer-events="none"></path><g class="uv-venv-vertical-benchmark_svg__mark-rule uv-venv-vertical-benchmark_svg__role-axis-grid" pointer-events="none"><path stroke="rgba(127,127,127,0.25)" d="M107.5 249.5v-90M201.5 249.5v-90M295.5 249.5v-90M388.5 249.5v-90"></path></g></g><g class="uv-venv-vertical-benchmark_svg__mark-group uv-venv-vertical-benchmark_svg__role-axis" aria-roledescription="axis" aria-label="X-axis for a linear scale with values from 0.0 to 1.6"><path class="uv-venv-vertical-benchmark_svg__background" aria-hidden="true" d="M107.5 249.5Z" pointer-events="none"></path><g class="uv-venv-vertical-benchmark_svg__mark-rule uv-venv-vertical-benchmark_svg__role-axis-tick" pointer-events="none"><path stroke="rgba(127,127,127,0.25)" d="M388.5 249.5"></path></g><g class="uv-venv-vertical-benchmark_svg__mark-text uv-venv-vertical-benchmark_svg__role-axis-label" pointer-events="none"><text text-anchor="middle" transform="translate(107.5 264.5)" font-family="Roboto Mono,monospace" font-size="12" class="uv-venv-vertical-benchmark_svg__benchmarkLabel">0s
  195. </text><text text-anchor="middle" transform="translate(201.25 264.5)" font-family="Roboto Mono,monospace" font-size="12" class="uv-venv-vertical-benchmark_svg__benchmarkLabel">0.5s
  196. </text><text text-anchor="middle" transform="translate(295 264.5)" font-family="Roboto Mono,monospace" font-size="12" class="uv-venv-vertical-benchmark_svg__benchmarkLabel">1s
  197. </text><text text-anchor="middle" transform="translate(388.75 264.5)" font-family="Roboto Mono,monospace" font-size="12" class="uv-venv-vertical-benchmark_svg__benchmarkLabel">1.5s
  198. </text></g></g><g class="uv-venv-vertical-benchmark_svg__mark-rect uv-venv-vertical-benchmark_svg__role-mark uv-venv-vertical-benchmark_svg__child_layer_0_marks" aria-roledescription="rect mark container"><path aria-label="Sum of time: 0.0182; tool: uv" aria-roledescription="bar" d="M107 167.5h3.413v13H107Z" class="uv-venv-vertical-benchmark_svg__benchmarkBar"></path><path aria-label="Sum of time: 0.1414; tool: virtualenv" aria-roledescription="bar" d="M107 197.5h26.512v13H107Z" class="uv-venv-vertical-benchmark_svg__benchmarkBar"></path><path aria-label="Sum of time: 1.54; tool: venv" aria-roledescription="bar" d="M107 227.5h288.75v13H107Z" class="uv-venv-vertical-benchmark_svg__benchmarkBar"></path></g><g class="uv-venv-vertical-benchmark_svg__mark-text uv-venv-vertical-benchmark_svg__role-mark uv-venv-vertical-benchmark_svg__child_layer_1_marks" aria-roledescription="text mark container"><text aria-label="Sum of time: 0.1414; tool: virtualenv; timeFormat: 141.4ms" aria-roledescription="text mark" transform="translate(139.512 208)" font-family="Roboto Mono,monospace" font-size="12" class="uv-venv-vertical-benchmark_svg__benchmarkLabel">141.4ms
  199. </text><text aria-label="Sum of time: 1.54; tool: venv; timeFormat: 1.54s" aria-roledescription="text mark" transform="translate(401.75 238)" font-family="Roboto Mono,monospace" font-size="12" class="uv-venv-vertical-benchmark_svg__benchmarkLabel">1.54s
  200. </text></g><g class="uv-venv-vertical-benchmark_svg__mark-text uv-venv-vertical-benchmark_svg__role-mark uv-venv-vertical-benchmark_svg__child_layer_2_marks" aria-roledescription="text mark container"><text aria-label="Sum of time: 0.0182; tool: uv; timeFormat: 18.2ms" aria-roledescription="text mark" transform="translate(116.412 178)" font-family="Roboto Mono,monospace" font-size="12" font-weight="bold" class="uv-venv-vertical-benchmark_svg__benchmarkLabel">18.2ms
  201. </text></g></g></g></svg></div><div class="hidden md:block"><div class="flex flex-row items-center justify-center text-flare"><div class="w-full md:w-[484px]"><svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 463 139"><g class="uv-venv-seed-benchmark_svg__mark-group uv-venv-seed-benchmark_svg__role-frame uv-venv-seed-benchmark_svg__root" aria-roledescription="group mark container" fill="none" stroke-miterlimit="10"><path class="uv-venv-seed-benchmark_svg__background" aria-hidden="true" d="M99 16h300v90H99Z"></path><g class="uv-venv-seed-benchmark_svg__mark-group uv-venv-seed-benchmark_svg__role-axis" aria-hidden="true"><path class="uv-venv-seed-benchmark_svg__background" aria-hidden="true" d="M99.5 106.5Z" pointer-events="none"></path><g class="uv-venv-seed-benchmark_svg__mark-rule uv-venv-seed-benchmark_svg__role-axis-grid" pointer-events="none"><path stroke="rgba(127,127,127,0.25)" d="M99.5 106.5v-90M193.5 106.5v-90M287.5 106.5v-90M380.5 106.5v-90"></path></g></g><g class="uv-venv-seed-benchmark_svg__mark-group uv-venv-seed-benchmark_svg__role-axis" aria-roledescription="axis" aria-label="X-axis for a linear scale with values from 0.0 to 1.6"><path class="uv-venv-seed-benchmark_svg__background" aria-hidden="true" d="M99.5 106.5Z" pointer-events="none"></path><g class="uv-venv-seed-benchmark_svg__mark-rule uv-venv-seed-benchmark_svg__role-axis-tick" pointer-events="none"><path stroke="rgba(127,127,127,0.25)" d="M380.5 106.5"></path></g><g class="uv-venv-seed-benchmark_svg__mark-text uv-venv-seed-benchmark_svg__role-axis-label" pointer-events="none"><text text-anchor="middle" transform="translate(99.5 121.5)" font-family="Roboto Mono,monospace" font-size="12" class="uv-venv-seed-benchmark_svg__benchmarkLabel">
  202. 0s
  203. </text><text text-anchor="middle" transform="translate(193.25 121.5)" font-family="Roboto Mono,monospace" font-size="12" class="uv-venv-seed-benchmark_svg__benchmarkLabel">
  204. 0.5s
  205. </text><text text-anchor="middle" transform="translate(287 121.5)" font-family="Roboto Mono,monospace" font-size="12" class="uv-venv-seed-benchmark_svg__benchmarkLabel">
  206. 1s
  207. </text><text text-anchor="middle" transform="translate(380.75 121.5)" font-family="Roboto Mono,monospace" font-size="12" class="uv-venv-seed-benchmark_svg__benchmarkLabel">
  208. 1.5s
  209. </text></g></g><g class="uv-venv-seed-benchmark_svg__mark-group uv-venv-seed-benchmark_svg__role-axis" aria-roledescription="axis" aria-label="Y-axis for a discrete scale with 3 values: uv, virtualenv, venv"><path class="uv-venv-seed-benchmark_svg__background" aria-hidden="true" d="M99.5 16.5Z" pointer-events="none"></path><g class="uv-venv-seed-benchmark_svg__mark-text uv-venv-seed-benchmark_svg__role-axis-label" pointer-events="none"><text text-anchor="end" transform="translate(89.5 35)" font-family="Roboto Mono,monospace" font-size="12" class="uv-venv-seed-benchmark_svg__benchmarkLabel" font-weight="bold">
  210. uv
  211. </text><text text-anchor="end" transform="translate(89.5 65)" font-family="Roboto Mono,monospace" font-size="12" class="uv-venv-seed-benchmark_svg__benchmarkLabel">
  212. virtualenv
  213. </text><text text-anchor="end" transform="translate(89.5 95)" font-family="Roboto Mono,monospace" font-size="12" class="uv-venv-seed-benchmark_svg__benchmarkLabel">
  214. venv
  215. </text></g></g><g class="uv-venv-seed-benchmark_svg__mark-rect uv-venv-seed-benchmark_svg__role-mark uv-venv-seed-benchmark_svg__layer_0_marks" aria-roledescription="rect mark container"><path aria-label="Sum of time: 0.0182; tool: uv" aria-roledescription="bar" d="M99 24.5h3.413v13H99Z" class="uv-venv-seed-benchmark_svg__benchmarkBar"></path><path aria-label="Sum of time: 0.1414; tool: virtualenv" aria-roledescription="bar" d="M99 54.5h26.512v13H99Z" class="uv-venv-seed-benchmark_svg__benchmarkBar"></path><path aria-label="Sum of time: 1.54; tool: venv" aria-roledescription="bar" d="M99 84.5h288.75v13H99Z" class="uv-venv-seed-benchmark_svg__benchmarkBar"></path></g><g class="uv-venv-seed-benchmark_svg__mark-text uv-venv-seed-benchmark_svg__role-mark uv-venv-seed-benchmark_svg__layer_1_marks" aria-roledescription="text mark container"><text aria-label="Sum of time: 0.1414; tool: virtualenv; timeFormat: 141.4ms" aria-roledescription="text mark" transform="translate(131.512 65)" font-family="Roboto Mono,monospace" font-size="12" class="uv-venv-seed-benchmark_svg__benchmarkLabel">141.4ms
  216. </text><text aria-label="Sum of time: 1.54; tool: venv; timeFormat: 1.54s" aria-roledescription="text mark" transform="translate(393.75 95)" font-family="Roboto Mono,monospace" font-size="12" class="uv-venv-seed-benchmark_svg__benchmarkLabel">1.54s
  217. </text></g><g class="uv-venv-seed-benchmark_svg__mark-text uv-venv-seed-benchmark_svg__role-mark uv-venv-seed-benchmark_svg__layer_2_marks" aria-roledescription="text mark container"><text aria-label="Sum of time: 0.0182; tool: uv; timeFormat: 18.2ms" aria-roledescription="text mark" transform="translate(108.412 35)" font-family="Roboto Mono,monospace" font-size="12" font-weight="bold" class="uv-venv-seed-benchmark_svg__benchmarkLabel">18.2ms
  218. </text></g></g></svg></div><div class="w-full md:w-[484px]"><svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 463 139"><g class="uv-venv-no-seed-benchmark_svg__mark-group uv-venv-no-seed-benchmark_svg__role-frame uv-venv-no-seed-benchmark_svg__root" aria-roledescription="group mark container" fill="none" stroke-miterlimit="10"><path class="uv-venv-no-seed-benchmark_svg__background" aria-hidden="true" d="M99 16h300v90H99Z"></path><g class="uv-venv-no-seed-benchmark_svg__mark-group uv-venv-no-seed-benchmark_svg__role-axis" aria-hidden="true"><path class="uv-venv-no-seed-benchmark_svg__background" aria-hidden="true" d="M99.5 106.5Z" pointer-events="none"></path><g class="uv-venv-no-seed-benchmark_svg__mark-rule uv-venv-no-seed-benchmark_svg__role-axis-grid" pointer-events="none"><path stroke="rgba(127,127,127,0.25)" d="M99.5 106.5v-90M174.5 106.5v-90M249.5 106.5v-90M324.5 106.5v-90M399.5 106.5v-90"></path></g></g><g class="uv-venv-no-seed-benchmark_svg__mark-group uv-venv-no-seed-benchmark_svg__role-axis" aria-roledescription="axis" aria-label="X-axis for a linear scale with values from 0.00 to 0.08"><path class="uv-venv-no-seed-benchmark_svg__background" aria-hidden="true" d="M99.5 106.5Z" pointer-events="none"></path><g class="uv-venv-no-seed-benchmark_svg__mark-rule uv-venv-no-seed-benchmark_svg__role-axis-tick" pointer-events="none"><path stroke="rgba(127,127,127,0.25)" d="M399.5 106.5"></path></g><g class="uv-venv-no-seed-benchmark_svg__mark-text uv-venv-no-seed-benchmark_svg__role-axis-label" pointer-events="none"><text text-anchor="middle" transform="translate(99.5 121.5)" font-family="Roboto Mono,monospace" font-size="12" class="uv-venv-no-seed-benchmark_svg__benchmarkLabel">
  219. 0s
  220. </text><text text-anchor="middle" transform="translate(174.5 121.5)" font-family="Roboto Mono,monospace" font-size="12" class="uv-venv-no-seed-benchmark_svg__benchmarkLabel">
  221. 0.02s
  222. </text><text text-anchor="middle" transform="translate(249.5 121.5)" font-family="Roboto Mono,monospace" font-size="12" class="uv-venv-no-seed-benchmark_svg__benchmarkLabel">
  223. 0.04s
  224. </text><text text-anchor="middle" transform="translate(324.5 121.5)" font-family="Roboto Mono,monospace" font-size="12" class="uv-venv-no-seed-benchmark_svg__benchmarkLabel">
  225. 0.06s
  226. </text><text text-anchor="middle" transform="translate(399.5 121.5)" font-family="Roboto Mono,monospace" font-size="12" class="uv-venv-no-seed-benchmark_svg__benchmarkLabel">
  227. 0.08s
  228. </text></g></g><g class="uv-venv-no-seed-benchmark_svg__mark-group uv-venv-no-seed-benchmark_svg__role-axis" aria-roledescription="axis" aria-label="Y-axis for a discrete scale with 3 values: uv, virtualenv, venv"><path class="uv-venv-no-seed-benchmark_svg__background" aria-hidden="true" d="M99.5 16.5Z" pointer-events="none"></path><g class="uv-venv-no-seed-benchmark_svg__mark-text uv-venv-no-seed-benchmark_svg__role-axis-label" pointer-events="none"><text text-anchor="end" transform="translate(89.5 35)" font-family="Roboto Mono,monospace" font-size="12" class="uv-venv-no-seed-benchmark_svg__benchmarkLabel" font-weight="bold">
  229. uv
  230. </text><text text-anchor="end" transform="translate(89.5 65)" font-family="Roboto Mono,monospace" font-size="12" class="uv-venv-no-seed-benchmark_svg__benchmarkLabel">
  231. virtualenv
  232. </text><text text-anchor="end" transform="translate(89.5 95)" font-family="Roboto Mono,monospace" font-size="12" class="uv-venv-no-seed-benchmark_svg__benchmarkLabel">
  233. venv
  234. </text></g></g><g class="uv-venv-no-seed-benchmark_svg__mark-rect uv-venv-no-seed-benchmark_svg__role-mark uv-venv-no-seed-benchmark_svg__layer_0_marks" aria-roledescription="rect mark container"><path aria-label="Sum of time: 0.0041; tool: uv" aria-roledescription="bar" d="M99 24.5h15.375v13H99Z" class="uv-venv-no-seed-benchmark_svg__benchmarkBar"></path><path aria-label="Sum of time: 0.0744; tool: virtualenv" aria-roledescription="bar" d="M99 54.5h279v13H99Z" class="uv-venv-no-seed-benchmark_svg__benchmarkBar"></path><path aria-label="Sum of time: 0.0241; tool: venv" aria-roledescription="bar" d="M99 84.5h90.375v13H99Z" class="uv-venv-no-seed-benchmark_svg__benchmarkBar"></path></g><g class="uv-venv-no-seed-benchmark_svg__mark-text uv-venv-no-seed-benchmark_svg__role-mark uv-venv-no-seed-benchmark_svg__layer_1_marks" aria-roledescription="text mark container"><text aria-label="Sum of time: 0.0744; tool: virtualenv; timeFormat: 74.4ms" aria-roledescription="text mark" transform="translate(384 65)" font-family="Roboto Mono,monospace" font-size="12" class="uv-venv-no-seed-benchmark_svg__benchmarkLabel">74.4ms
  235. </text><text aria-label="Sum of time: 0.0241; tool: venv; timeFormat: 24.1ms" aria-roledescription="text mark" transform="translate(195.375 95)" font-family="Roboto Mono,monospace" font-size="12" class="uv-venv-no-seed-benchmark_svg__benchmarkLabel">24.1ms
  236. </text></g><g class="uv-venv-no-seed-benchmark_svg__mark-text uv-venv-no-seed-benchmark_svg__role-mark uv-venv-no-seed-benchmark_svg__layer_2_marks" aria-roledescription="text mark container"><text aria-label="Sum of time: 0.0041; tool: uv; timeFormat: 4.1ms" aria-roledescription="text mark" transform="translate(120.375 35)" font-family="Roboto Mono,monospace" font-size="12" font-weight="bold" class="uv-venv-no-seed-benchmark_svg__benchmarkLabel">4.1ms
  237. </text></g></g></svg></div></div></div><div class="flex flex-row items-center opacity-75"><p class="text-sm md:hidden">Creating a virtual environment, with (top) and without (bottom) seed packages like pip and setuptools (<a href="https://github.com/astral-sh/uv/blob/ea13d94c57149a8fc6ebfcef46149252e869269f/scripts/benchmarks/venv.sh" target="_blank" rel="noreferrer">source</a>).</p><p class="hidden text-sm md:block">Creating a virtual environment, with (left) and without (right) seed packages like pip and setuptools (<a href="https://github.com/astral-sh/uv/blob/ea13d94c57149a8fc6ebfcef46149252e869269f/scripts/benchmarks/venv.sh" target="_blank" rel="noreferrer">source</a>).</p></div></div>
  238. <p>uv's virtual environments are standards-compliant and work interchangeably with other tools —
  239. there's no lock-in or customization.</p>
  240. <p>Building our own package management stack from scratch also opened up room for new capabilities.
  241. For example:</p>
  242. <ul>
  243. <li><strong>uv supports alternate resolution strategies.</strong> By default, uv follows the standard
  244. Python dependency resolution strategy of preferring the latest compatible version of each package.
  245. But by passing <code>--resolution=lowest</code>, library authors can test their packages against the lowest-compatible version of their dependencies. (This is similar to Go's
  246. <a href="https://go.dev/ref/mod#minimal-version-selection">Minimal version selection</a>.)</li>
  247. <li><strong>uv allows for resolutions against arbitrary target Python versions.</strong> While <code>pip</code>
  248. and <code>pip-tools</code> always resolve against the currently-installed Python version (generating, e.g., a
  249. Python 3.12-compatible resolution when running under Python 3.12), uv accepts
  250. a <code>--python-version</code> parameter, enabling you to generate, e.g., Python 3.7-compatible resolutions
  251. even when running under newer versions.</li>
  252. <li><strong>uv allows for dependency “overrides”.</strong> uv takes pip's “constraints” concepts a step
  253. further via overrides (<code>-o overrides.txt</code>), which allow the user to guide the resolver by
  254. overriding the declared dependencies of a package. Overrides give the user an escape hatch for
  255. working around erroneous upper bounds and other incorrectly-declared dependencies.</li>
  256. </ul>
  257. <p>In its current form, uv won't be the right fit for all projects. <code>pip</code> is a mature and stable
  258. tool, with extensive support for an extremely wide range of use cases and a focus on compatibility.
  259. While uv supports a large fraction of the <code>pip</code> interface, it lacks support for some of its
  260. legacy features, like <code>.egg</code> distributions.</p>
  261. <p>Similarly, uv does not yet generate a platform-agnostic lockfile. This matches <code>pip-tools</code>, but
  262. differs from Poetry and PDM, making uv a better fit for projects built around the <code>pip</code> and
  263. <code>pip-tools</code> workflows.</p>
  264. <p>For those deep in the packaging ecosystem, uv also includes standards-compliant Rust
  265. implementations of <a href="https://peps.python.org/pep-0440/">PEP 440</a> (version identifiers),
  266. <a href="https://peps.python.org/pep-0508/">PEP 508</a> (dependency specifiers),
  267. <a href="https://peps.python.org/pep-0517/">PEP 517</a> (a build-system independent build frontend),
  268. <a href="https://peps.python.org/pep-0405/">PEP 405</a> (virtual environments), and more.</p>
  269. <h3 class="hover:none group cursor-default"><span id="a-cargo-for-python-uv-and-rye" class="invisible absolute mt-[-24px] block pt-[24px]"></span>A "Cargo for Python": uv and Rye <a href="#a-cargo-for-python-uv-and-rye" class="hidden group-hover:inline-block">#</a></h3>
  270. <p>uv represents an intermediary milestone in our pursuit of a <a href="https://blog.rust-lang.org/2016/05/05/cargo-pillars.html#pillars-of-cargo">"Cargo for Python"</a>: a unified Python
  271. package and project manager that is extremely fast, reliable, and easy to use.</p>
  272. <p>Think: a single binary that bootstraps your Python installation and gives you everything you need to
  273. be productive with Python, bundling not only <code>pip</code>, <code>pip-tools</code>, and <code>virtualenv</code>, but also <code>pipx</code>,
  274. <code>tox</code>, <code>poetry</code>, <code>pyenv</code>, <code>ruff</code>, and more.</p>
  275. <p>Python tooling can be a low-confidence experience: it's a significant amount of work to stand up a
  276. new or existing project, and commands fail in confusing ways. In contrast, when working in the Rust
  277. ecosystem, you trust the tools to succeed. The Astral toolchain is about bringing Python from a
  278. low-confidence to a high-confidence experience.</p>
  279. <p>This vision for Python packaging is not far off from that put forward by <a href="https://github.com/mitsuhiko/rye">Rye</a>,
  280. an experimental project and package management tool from <a href="https://github.com/mitsuhiko">Armin Ronacher</a>.</p>
  281. <p>In talking with Armin, it was clear that our visions were closely aligned, but that fulfilling
  282. them would require a significant investment in foundational tooling. For example: building such a
  283. tool requires an extremely fast, end-to-end integrated, cross-platform resolver and installer. <strong>In
  284. uv, we've built that foundational tooling.</strong></p>
  285. <p>We saw this as a rare opportunity to team up, and to avoid fragmenting the Python ecosystem.
  286. <strong>As such, in collaboration with Armin, we're excited to be taking over <a href="https://github.com/mitsuhiko/rye">Rye</a>.</strong>
  287. Our goal is to evolve uv into a production-ready <a href="https://blog.rust-lang.org/2016/05/05/cargo-pillars.html#pillars-of-cargo">"Cargo for Python"</a>, and to provide a smooth
  288. migration path from Rye to uv when the time is right.</p>
  289. <p>Until then, we'll be maintaining Rye, migrating it to use uv under-the-hood, and, more
  290. generally, treating it as an experimental testbed for the end-user experience we're building
  291. towards.</p>
  292. <p>While merging projects comes with its own challenges, we're committed to building a single, unified
  293. tool under the Astral banner, and to supporting existing Rye users as we evolve uv into a
  294. suitable and comprehensive successor project.</p>
  295. <h3 class="hover:none group cursor-default"><span id="our-roadmap" class="invisible absolute mt-[-24px] block pt-[24px]"></span>Our Roadmap <a href="#our-roadmap" class="hidden group-hover:inline-block">#</a></h3>
  296. <p>Following this release, our first priority is to support users as they consider <a href="https://github.com/astral-sh/uv">uv</a>,
  297. with a focus on improving compatibility, performance, and stability across platforms.</p>
  298. <p>From there, we'll look towards expanding uv into a complete Python project and package manager:
  299. a single binary that gives you everything you need to be productive with Python.</p>
  300. <p>We have an ambitious roadmap for uv. But even in its current form, I think it will
  301. feel like a very different experience for Python. I hope you'll give it a try.</p>
  302. <h3 class="hover:none group cursor-default"><span id="acknowledgements" class="invisible absolute mt-[-24px] block pt-[24px]"></span>Acknowledgements <a href="#acknowledgements" class="hidden group-hover:inline-block">#</a></h3>
  303. <p>Finally, we'd like to thank all those that contributed directly or indirectly to the development of
  304. uv. Foremost among them are <a href="https://github.com/Eh2406">Jacob Finkelman</a>
  305. and <a href="https://github.com/mpizenberg">Matthieu Pizenberg</a>, the maintainers
  306. of <a href="https://github.com/pubgrub-rs/pubgrub">pubgrub-rs</a>. uv uses PubGrub as its underlying
  307. version solver, and we're grateful to Jacob and Matthieu for the work they put into PubGrub in the
  308. past, and for the way they've engaged with us as collaborators throughout the project.</p>
  309. <p>We'd also like to thank those projects in the packaging space that've inspired us,
  310. especially <a href="https://github.com/rust-lang/cargo">Cargo</a>, along with <a href="https://github.com/oven-sh/bun">Bun</a>, <a href="https://github.com/orogene/orogene">Orogene</a>,
  311. and <a href="https://github.com/pnpm/pnpm">pnpm</a> from the JavaScript ecosystem,
  312. and <a href="https://github.com/njsmith/posy">Posy</a>, <a href="https://github.com/konstin/monotrail-resolve">Monotrail</a>,
  313. and <a href="https://github.com/mitsuhiko/rye">Rye</a> from the Python ecosystem. In particular, thanks
  314. to <a href="https://github.com/mitsuhiko">Armin Ronacher</a> for collaborating with us on this effort.</p>
  315. <p>Finally, we'd like to thank the maintainers of <a href="https://github.com/pypa/pip">pip</a> and the members of
  316. the PyPA more broadly for all the work they do to make Python packaging possible.</p>
  317. </article>
  318. <hr>
  319. <footer>
  320. <p>
  321. <a href="/david/" title="Aller à l’accueil"><svg class="icon icon-home">
  322. <use xlink:href="/static/david/icons2/symbol-defs-2021-12.svg#icon-home"></use>
  323. </svg> Accueil</a> •
  324. <a href="/david/log/" title="Accès au flux RSS"><svg class="icon icon-rss2">
  325. <use xlink:href="/static/david/icons2/symbol-defs-2021-12.svg#icon-rss2"></use>
  326. </svg> Suivre</a> •
  327. <a href="http://larlet.com" title="Go to my English profile" data-instant><svg class="icon icon-user-tie">
  328. <use xlink:href="/static/david/icons2/symbol-defs-2021-12.svg#icon-user-tie"></use>
  329. </svg> Pro</a> •
  330. <a href="mailto:david%40larlet.fr" title="Envoyer un courriel"><svg class="icon icon-mail">
  331. <use xlink:href="/static/david/icons2/symbol-defs-2021-12.svg#icon-mail"></use>
  332. </svg> Email</a> •
  333. <abbr class="nowrap" title="Hébergeur : Alwaysdata, 62 rue Tiquetonne 75002 Paris, +33184162340"><svg class="icon icon-hammer2">
  334. <use xlink:href="/static/david/icons2/symbol-defs-2021-12.svg#icon-hammer2"></use>
  335. </svg> Légal</abbr>
  336. </p>
  337. <template id="theme-selector">
  338. <form>
  339. <fieldset>
  340. <legend><svg class="icon icon-brightness-contrast">
  341. <use xlink:href="/static/david/icons2/symbol-defs-2021-12.svg#icon-brightness-contrast"></use>
  342. </svg> Thème</legend>
  343. <label>
  344. <input type="radio" value="auto" name="chosen-color-scheme" checked> Auto
  345. </label>
  346. <label>
  347. <input type="radio" value="dark" name="chosen-color-scheme"> Foncé
  348. </label>
  349. <label>
  350. <input type="radio" value="light" name="chosen-color-scheme"> Clair
  351. </label>
  352. </fieldset>
  353. </form>
  354. </template>
  355. </footer>
  356. <script src="/static/david/js/instantpage-5.1.0.min.js" type="module"></script>
  357. <script>
  358. function loadThemeForm(templateName) {
  359. const themeSelectorTemplate = document.querySelector(templateName)
  360. const form = themeSelectorTemplate.content.firstElementChild
  361. themeSelectorTemplate.replaceWith(form)
  362. form.addEventListener('change', (e) => {
  363. const chosenColorScheme = e.target.value
  364. localStorage.setItem('theme', chosenColorScheme)
  365. toggleTheme(chosenColorScheme)
  366. })
  367. const selectedTheme = localStorage.getItem('theme')
  368. if (selectedTheme && selectedTheme !== 'undefined') {
  369. form.querySelector(`[value="${selectedTheme}"]`).checked = true
  370. }
  371. }
  372. const prefersColorSchemeDark = '(prefers-color-scheme: dark)'
  373. window.addEventListener('load', () => {
  374. let hasDarkRules = false
  375. for (const styleSheet of Array.from(document.styleSheets)) {
  376. let mediaRules = []
  377. for (const cssRule of styleSheet.cssRules) {
  378. if (cssRule.type !== CSSRule.MEDIA_RULE) {
  379. continue
  380. }
  381. // WARNING: Safari does not have/supports `conditionText`.
  382. if (cssRule.conditionText) {
  383. if (cssRule.conditionText !== prefersColorSchemeDark) {
  384. continue
  385. }
  386. } else {
  387. if (cssRule.cssText.startsWith(prefersColorSchemeDark)) {
  388. continue
  389. }
  390. }
  391. mediaRules = mediaRules.concat(Array.from(cssRule.cssRules))
  392. }
  393. // WARNING: do not try to insert a Rule to a styleSheet you are
  394. // currently iterating on, otherwise the browser will be stuck
  395. // in a infinite loop…
  396. for (const mediaRule of mediaRules) {
  397. styleSheet.insertRule(mediaRule.cssText)
  398. hasDarkRules = true
  399. }
  400. }
  401. if (hasDarkRules) {
  402. loadThemeForm('#theme-selector')
  403. }
  404. })
  405. </script>
  406. </body>
  407. </html>