From 2d02a82e3a568cdb61a4bc8102b98c894da242c7 Mon Sep 17 00:00:00 2001 From: mitsuhiko Date: Sat, 20 Jan 2024 19:13:08 +0000 Subject: [PATCH] Deployed 20e605e with MkDocs version: 1.4.3 --- .nojekyll | 0 404.html | 776 ++ CNAME | 1 + assets/images/favicon.png | Bin 0 -> 1870 bytes assets/javascripts/bundle.c2be25ad.min.js | 29 + assets/javascripts/bundle.c2be25ad.min.js.map | 8 + assets/javascripts/lunr/min/lunr.ar.min.js | 1 + assets/javascripts/lunr/min/lunr.da.min.js | 18 + assets/javascripts/lunr/min/lunr.de.min.js | 18 + assets/javascripts/lunr/min/lunr.du.min.js | 18 + assets/javascripts/lunr/min/lunr.es.min.js | 18 + assets/javascripts/lunr/min/lunr.fi.min.js | 18 + assets/javascripts/lunr/min/lunr.fr.min.js | 18 + assets/javascripts/lunr/min/lunr.hi.min.js | 1 + assets/javascripts/lunr/min/lunr.hu.min.js | 18 + assets/javascripts/lunr/min/lunr.hy.min.js | 1 + assets/javascripts/lunr/min/lunr.it.min.js | 18 + assets/javascripts/lunr/min/lunr.ja.min.js | 1 + assets/javascripts/lunr/min/lunr.jp.min.js | 1 + assets/javascripts/lunr/min/lunr.kn.min.js | 1 + assets/javascripts/lunr/min/lunr.ko.min.js | 1 + assets/javascripts/lunr/min/lunr.multi.min.js | 1 + assets/javascripts/lunr/min/lunr.nl.min.js | 18 + assets/javascripts/lunr/min/lunr.no.min.js | 18 + assets/javascripts/lunr/min/lunr.pt.min.js | 18 + assets/javascripts/lunr/min/lunr.ro.min.js | 18 + assets/javascripts/lunr/min/lunr.ru.min.js | 18 + assets/javascripts/lunr/min/lunr.sa.min.js | 1 + .../lunr/min/lunr.stemmer.support.min.js | 1 + assets/javascripts/lunr/min/lunr.sv.min.js | 18 + assets/javascripts/lunr/min/lunr.ta.min.js | 1 + assets/javascripts/lunr/min/lunr.te.min.js | 1 + assets/javascripts/lunr/min/lunr.th.min.js | 1 + assets/javascripts/lunr/min/lunr.tr.min.js | 18 + assets/javascripts/lunr/min/lunr.vi.min.js | 1 + assets/javascripts/lunr/min/lunr.zh.min.js | 1 + assets/javascripts/lunr/tinyseg.js | 206 + assets/javascripts/lunr/wordcut.js | 6708 +++++++++++++++++ .../workers/search.208ed371.min.js | 42 + .../workers/search.208ed371.min.js.map | 8 + assets/stylesheets/main.85bb2934.min.css | 1 + assets/stylesheets/main.85bb2934.min.css.map | 1 + assets/stylesheets/palette.a6bdf11c.min.css | 1 + .../stylesheets/palette.a6bdf11c.min.css.map | 1 + changelog/index.html | 1587 ++++ community/index.html | 866 +++ get | 82 + guide/basics/index.html | 1001 +++ guide/config/index.html | 1027 +++ guide/deps/index.html | 940 +++ guide/faq/index.html | 1009 +++ guide/index.html | 869 +++ guide/installation/index.html | 1200 +++ guide/publish/index.html | 940 +++ guide/pyproject/index.html | 1099 +++ guide/rust/index.html | 927 +++ guide/shims/index.html | 914 +++ guide/sources/index.html | 1028 +++ guide/sync/index.html | 1001 +++ guide/toolchains/cpython/index.html | 945 +++ guide/toolchains/index.html | 1002 +++ guide/toolchains/pypy/index.html | 920 +++ guide/tools/index.html | 944 +++ hooks.py | 6 + index.html | 918 +++ philosophy/index.html | 1266 ++++ search/search_index.json | 1 + sitemap.xml | 3 + sitemap.xml.gz | Bin 0 -> 127 bytes static/banner-dark.png | Bin 0 -> 40057 bytes static/banner.png | Bin 0 -> 42371 bytes static/extra.css | 104 + static/favicon.svg | 14 + static/logo.svg | 1 + 74 files changed, 28681 insertions(+) create mode 100644 .nojekyll create mode 100644 404.html create mode 100644 CNAME create mode 100644 assets/images/favicon.png create mode 100644 assets/javascripts/bundle.c2be25ad.min.js create mode 100644 assets/javascripts/bundle.c2be25ad.min.js.map create mode 100644 assets/javascripts/lunr/min/lunr.ar.min.js create mode 100644 assets/javascripts/lunr/min/lunr.da.min.js create mode 100644 assets/javascripts/lunr/min/lunr.de.min.js create mode 100644 assets/javascripts/lunr/min/lunr.du.min.js create mode 100644 assets/javascripts/lunr/min/lunr.es.min.js create mode 100644 assets/javascripts/lunr/min/lunr.fi.min.js create mode 100644 assets/javascripts/lunr/min/lunr.fr.min.js create mode 100644 assets/javascripts/lunr/min/lunr.hi.min.js create mode 100644 assets/javascripts/lunr/min/lunr.hu.min.js create mode 100644 assets/javascripts/lunr/min/lunr.hy.min.js create mode 100644 assets/javascripts/lunr/min/lunr.it.min.js create mode 100644 assets/javascripts/lunr/min/lunr.ja.min.js create mode 100644 assets/javascripts/lunr/min/lunr.jp.min.js create mode 100644 assets/javascripts/lunr/min/lunr.kn.min.js create mode 100644 assets/javascripts/lunr/min/lunr.ko.min.js create mode 100644 assets/javascripts/lunr/min/lunr.multi.min.js create mode 100644 assets/javascripts/lunr/min/lunr.nl.min.js create mode 100644 assets/javascripts/lunr/min/lunr.no.min.js create mode 100644 assets/javascripts/lunr/min/lunr.pt.min.js create mode 100644 assets/javascripts/lunr/min/lunr.ro.min.js create mode 100644 assets/javascripts/lunr/min/lunr.ru.min.js create mode 100644 assets/javascripts/lunr/min/lunr.sa.min.js create mode 100644 assets/javascripts/lunr/min/lunr.stemmer.support.min.js create mode 100644 assets/javascripts/lunr/min/lunr.sv.min.js create mode 100644 assets/javascripts/lunr/min/lunr.ta.min.js create mode 100644 assets/javascripts/lunr/min/lunr.te.min.js create mode 100644 assets/javascripts/lunr/min/lunr.th.min.js create mode 100644 assets/javascripts/lunr/min/lunr.tr.min.js create mode 100644 assets/javascripts/lunr/min/lunr.vi.min.js create mode 100644 assets/javascripts/lunr/min/lunr.zh.min.js create mode 100644 assets/javascripts/lunr/tinyseg.js create mode 100644 assets/javascripts/lunr/wordcut.js create mode 100644 assets/javascripts/workers/search.208ed371.min.js create mode 100644 assets/javascripts/workers/search.208ed371.min.js.map create mode 100644 assets/stylesheets/main.85bb2934.min.css create mode 100644 assets/stylesheets/main.85bb2934.min.css.map create mode 100644 assets/stylesheets/palette.a6bdf11c.min.css create mode 100644 assets/stylesheets/palette.a6bdf11c.min.css.map create mode 100644 changelog/index.html create mode 100644 community/index.html create mode 100755 get create mode 100644 guide/basics/index.html create mode 100644 guide/config/index.html create mode 100644 guide/deps/index.html create mode 100644 guide/faq/index.html create mode 100644 guide/index.html create mode 100644 guide/installation/index.html create mode 100644 guide/publish/index.html create mode 100644 guide/pyproject/index.html create mode 100644 guide/rust/index.html create mode 100644 guide/shims/index.html create mode 100644 guide/sources/index.html create mode 100644 guide/sync/index.html create mode 100644 guide/toolchains/cpython/index.html create mode 100644 guide/toolchains/index.html create mode 100644 guide/toolchains/pypy/index.html create mode 100644 guide/tools/index.html create mode 100644 hooks.py create mode 100644 index.html create mode 100644 philosophy/index.html create mode 100644 search/search_index.json create mode 100644 sitemap.xml create mode 100644 sitemap.xml.gz create mode 100644 static/banner-dark.png create mode 100644 static/banner.png create mode 100644 static/extra.css create mode 100644 static/favicon.svg create mode 100644 static/logo.svg diff --git a/.nojekyll b/.nojekyll new file mode 100644 index 0000000000..e69de29bb2 diff --git a/404.html b/404.html new file mode 100644 index 0000000000..f2ff74399e --- /dev/null +++ b/404.html @@ -0,0 +1,776 @@ + + + + + + + + + + + + + + + + + + + + Rye + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + + +
+
+
+ + + + +
+
+ +

404 - Not found

+ +
+
+ + + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/CNAME b/CNAME new file mode 100644 index 0000000000..ced6063925 --- /dev/null +++ b/CNAME @@ -0,0 +1 @@ +rye-up.com diff --git a/assets/images/favicon.png b/assets/images/favicon.png new file mode 100644 index 0000000000000000000000000000000000000000..1cf13b9f9d978896599290a74f77d5dbe7d1655c GIT binary patch literal 1870 zcmV-U2eJ5xP)Gc)JR9QMau)O=X#!i9;T z37kk-upj^(fsR36MHs_+1RCI)NNu9}lD0S{B^g8PN?Ww(5|~L#Ng*g{WsqleV}|#l zz8@ri&cTzw_h33bHI+12+kK6WN$h#n5cD8OQt`5kw6p~9H3()bUQ8OS4Q4HTQ=1Ol z_JAocz`fLbT2^{`8n~UAo=#AUOf=SOq4pYkt;XbC&f#7lb$*7=$na!mWCQ`dBQsO0 zLFBSPj*N?#u5&pf2t4XjEGH|=pPQ8xh7tpx;US5Cx_Ju;!O`ya-yF`)b%TEt5>eP1ZX~}sjjA%FJF?h7cX8=b!DZl<6%Cv z*G0uvvU+vmnpLZ2paivG-(cd*y3$hCIcsZcYOGh{$&)A6*XX&kXZd3G8m)G$Zz-LV z^GF3VAW^Mdv!)4OM8EgqRiz~*Cji;uzl2uC9^=8I84vNp;ltJ|q-*uQwGp2ma6cY7 z;`%`!9UXO@fr&Ebapfs34OmS9^u6$)bJxrucutf>`dKPKT%%*d3XlFVKunp9 zasduxjrjs>f8V=D|J=XNZp;_Zy^WgQ$9WDjgY=z@stwiEBm9u5*|34&1Na8BMjjgf3+SHcr`5~>oz1Y?SW^=K z^bTyO6>Gar#P_W2gEMwq)ot3; zREHn~U&Dp0l6YT0&k-wLwYjb?5zGK`W6S2v+K>AM(95m2C20L|3m~rN8dprPr@t)5lsk9Hu*W z?pS990s;Ez=+Rj{x7p``4>+c0G5^pYnB1^!TL=(?HLHZ+HicG{~4F1d^5Awl_2!1jICM-!9eoLhbbT^;yHcefyTAaqRcY zmuctDopPT!%k+}x%lZRKnzykr2}}XfG_ne?nRQO~?%hkzo;@RN{P6o`&mMUWBYMTe z6i8ChtjX&gXl`nvrU>jah)2iNM%JdjqoaeaU%yVn!^70x-flljp6Q5tK}5}&X8&&G zX3fpb3E(!rH=zVI_9Gjl45w@{(ITqngWFe7@9{mX;tO25Z_8 zQHEpI+FkTU#4xu>RkN>b3Tnc3UpWzPXWm#o55GKF09j^Mh~)K7{QqbO_~(@CVq! zS<8954|P8mXN2MRs86xZ&Q4EfM@JB94b=(YGuk)s&^jiSF=t3*oNK3`rD{H`yQ?d; ztE=laAUoZx5?RC8*WKOj`%LXEkgDd>&^Q4M^z`%u0rg-It=hLCVsq!Z%^6eB-OvOT zFZ28TN&cRmgU}Elrnk43)!>Z1FCPL2K$7}gwzIc48NX}#!A1BpJP?#v5wkNprhV** z?Cpalt1oH&{r!o3eSKc&ap)iz2BTn_VV`4>9M^b3;(YY}4>#ML6{~(4mH+?%07*qo IM6N<$f(jP3KmY&$ literal 0 HcmV?d00001 diff --git a/assets/javascripts/bundle.c2be25ad.min.js b/assets/javascripts/bundle.c2be25ad.min.js new file mode 100644 index 0000000000..f32333ee14 --- /dev/null +++ b/assets/javascripts/bundle.c2be25ad.min.js @@ -0,0 +1,29 @@ +"use strict";(()=>{var Ci=Object.create;var gr=Object.defineProperty;var Ri=Object.getOwnPropertyDescriptor;var ki=Object.getOwnPropertyNames,Ht=Object.getOwnPropertySymbols,Hi=Object.getPrototypeOf,yr=Object.prototype.hasOwnProperty,nn=Object.prototype.propertyIsEnumerable;var rn=(e,t,r)=>t in e?gr(e,t,{enumerable:!0,configurable:!0,writable:!0,value:r}):e[t]=r,P=(e,t)=>{for(var r in t||(t={}))yr.call(t,r)&&rn(e,r,t[r]);if(Ht)for(var r of Ht(t))nn.call(t,r)&&rn(e,r,t[r]);return e};var on=(e,t)=>{var r={};for(var n in e)yr.call(e,n)&&t.indexOf(n)<0&&(r[n]=e[n]);if(e!=null&&Ht)for(var n of Ht(e))t.indexOf(n)<0&&nn.call(e,n)&&(r[n]=e[n]);return r};var Pt=(e,t)=>()=>(t||e((t={exports:{}}).exports,t),t.exports);var Pi=(e,t,r,n)=>{if(t&&typeof t=="object"||typeof t=="function")for(let o of ki(t))!yr.call(e,o)&&o!==r&&gr(e,o,{get:()=>t[o],enumerable:!(n=Ri(t,o))||n.enumerable});return e};var yt=(e,t,r)=>(r=e!=null?Ci(Hi(e)):{},Pi(t||!e||!e.__esModule?gr(r,"default",{value:e,enumerable:!0}):r,e));var sn=Pt((xr,an)=>{(function(e,t){typeof xr=="object"&&typeof an!="undefined"?t():typeof define=="function"&&define.amd?define(t):t()})(xr,function(){"use strict";function e(r){var n=!0,o=!1,i=null,s={text:!0,search:!0,url:!0,tel:!0,email:!0,password:!0,number:!0,date:!0,month:!0,week:!0,time:!0,datetime:!0,"datetime-local":!0};function a(O){return!!(O&&O!==document&&O.nodeName!=="HTML"&&O.nodeName!=="BODY"&&"classList"in O&&"contains"in O.classList)}function f(O){var Qe=O.type,De=O.tagName;return!!(De==="INPUT"&&s[Qe]&&!O.readOnly||De==="TEXTAREA"&&!O.readOnly||O.isContentEditable)}function c(O){O.classList.contains("focus-visible")||(O.classList.add("focus-visible"),O.setAttribute("data-focus-visible-added",""))}function u(O){O.hasAttribute("data-focus-visible-added")&&(O.classList.remove("focus-visible"),O.removeAttribute("data-focus-visible-added"))}function p(O){O.metaKey||O.altKey||O.ctrlKey||(a(r.activeElement)&&c(r.activeElement),n=!0)}function m(O){n=!1}function d(O){a(O.target)&&(n||f(O.target))&&c(O.target)}function h(O){a(O.target)&&(O.target.classList.contains("focus-visible")||O.target.hasAttribute("data-focus-visible-added"))&&(o=!0,window.clearTimeout(i),i=window.setTimeout(function(){o=!1},100),u(O.target))}function v(O){document.visibilityState==="hidden"&&(o&&(n=!0),Y())}function Y(){document.addEventListener("mousemove",N),document.addEventListener("mousedown",N),document.addEventListener("mouseup",N),document.addEventListener("pointermove",N),document.addEventListener("pointerdown",N),document.addEventListener("pointerup",N),document.addEventListener("touchmove",N),document.addEventListener("touchstart",N),document.addEventListener("touchend",N)}function B(){document.removeEventListener("mousemove",N),document.removeEventListener("mousedown",N),document.removeEventListener("mouseup",N),document.removeEventListener("pointermove",N),document.removeEventListener("pointerdown",N),document.removeEventListener("pointerup",N),document.removeEventListener("touchmove",N),document.removeEventListener("touchstart",N),document.removeEventListener("touchend",N)}function N(O){O.target.nodeName&&O.target.nodeName.toLowerCase()==="html"||(n=!1,B())}document.addEventListener("keydown",p,!0),document.addEventListener("mousedown",m,!0),document.addEventListener("pointerdown",m,!0),document.addEventListener("touchstart",m,!0),document.addEventListener("visibilitychange",v,!0),Y(),r.addEventListener("focus",d,!0),r.addEventListener("blur",h,!0),r.nodeType===Node.DOCUMENT_FRAGMENT_NODE&&r.host?r.host.setAttribute("data-js-focus-visible",""):r.nodeType===Node.DOCUMENT_NODE&&(document.documentElement.classList.add("js-focus-visible"),document.documentElement.setAttribute("data-js-focus-visible",""))}if(typeof window!="undefined"&&typeof document!="undefined"){window.applyFocusVisiblePolyfill=e;var t;try{t=new CustomEvent("focus-visible-polyfill-ready")}catch(r){t=document.createEvent("CustomEvent"),t.initCustomEvent("focus-visible-polyfill-ready",!1,!1,{})}window.dispatchEvent(t)}typeof document!="undefined"&&e(document)})});var cn=Pt(Er=>{(function(e){var t=function(){try{return!!Symbol.iterator}catch(c){return!1}},r=t(),n=function(c){var u={next:function(){var p=c.shift();return{done:p===void 0,value:p}}};return r&&(u[Symbol.iterator]=function(){return u}),u},o=function(c){return encodeURIComponent(c).replace(/%20/g,"+")},i=function(c){return decodeURIComponent(String(c).replace(/\+/g," "))},s=function(){var c=function(p){Object.defineProperty(this,"_entries",{writable:!0,value:{}});var m=typeof p;if(m!=="undefined")if(m==="string")p!==""&&this._fromString(p);else if(p instanceof c){var d=this;p.forEach(function(B,N){d.append(N,B)})}else if(p!==null&&m==="object")if(Object.prototype.toString.call(p)==="[object Array]")for(var h=0;hd[0]?1:0}),c._entries&&(c._entries={});for(var p=0;p1?i(d[1]):"")}})})(typeof global!="undefined"?global:typeof window!="undefined"?window:typeof self!="undefined"?self:Er);(function(e){var t=function(){try{var o=new e.URL("b","http://a");return o.pathname="c d",o.href==="http://a/c%20d"&&o.searchParams}catch(i){return!1}},r=function(){var o=e.URL,i=function(f,c){typeof f!="string"&&(f=String(f)),c&&typeof c!="string"&&(c=String(c));var u=document,p;if(c&&(e.location===void 0||c!==e.location.href)){c=c.toLowerCase(),u=document.implementation.createHTMLDocument(""),p=u.createElement("base"),p.href=c,u.head.appendChild(p);try{if(p.href.indexOf(c)!==0)throw new Error(p.href)}catch(O){throw new Error("URL unable to set base "+c+" due to "+O)}}var m=u.createElement("a");m.href=f,p&&(u.body.appendChild(m),m.href=m.href);var d=u.createElement("input");if(d.type="url",d.value=f,m.protocol===":"||!/:/.test(m.href)||!d.checkValidity()&&!c)throw new TypeError("Invalid URL");Object.defineProperty(this,"_anchorElement",{value:m});var h=new e.URLSearchParams(this.search),v=!0,Y=!0,B=this;["append","delete","set"].forEach(function(O){var Qe=h[O];h[O]=function(){Qe.apply(h,arguments),v&&(Y=!1,B.search=h.toString(),Y=!0)}}),Object.defineProperty(this,"searchParams",{value:h,enumerable:!0});var N=void 0;Object.defineProperty(this,"_updateSearchParams",{enumerable:!1,configurable:!1,writable:!1,value:function(){this.search!==N&&(N=this.search,Y&&(v=!1,this.searchParams._fromString(this.search),v=!0))}})},s=i.prototype,a=function(f){Object.defineProperty(s,f,{get:function(){return this._anchorElement[f]},set:function(c){this._anchorElement[f]=c},enumerable:!0})};["hash","host","hostname","port","protocol"].forEach(function(f){a(f)}),Object.defineProperty(s,"search",{get:function(){return this._anchorElement.search},set:function(f){this._anchorElement.search=f,this._updateSearchParams()},enumerable:!0}),Object.defineProperties(s,{toString:{get:function(){var f=this;return function(){return f.href}}},href:{get:function(){return this._anchorElement.href.replace(/\?$/,"")},set:function(f){this._anchorElement.href=f,this._updateSearchParams()},enumerable:!0},pathname:{get:function(){return this._anchorElement.pathname.replace(/(^\/?)/,"/")},set:function(f){this._anchorElement.pathname=f},enumerable:!0},origin:{get:function(){var f={"http:":80,"https:":443,"ftp:":21}[this._anchorElement.protocol],c=this._anchorElement.port!=f&&this._anchorElement.port!=="";return this._anchorElement.protocol+"//"+this._anchorElement.hostname+(c?":"+this._anchorElement.port:"")},enumerable:!0},password:{get:function(){return""},set:function(f){},enumerable:!0},username:{get:function(){return""},set:function(f){},enumerable:!0}}),i.createObjectURL=function(f){return o.createObjectURL.apply(o,arguments)},i.revokeObjectURL=function(f){return o.revokeObjectURL.apply(o,arguments)},e.URL=i};if(t()||r(),e.location!==void 0&&!("origin"in e.location)){var n=function(){return e.location.protocol+"//"+e.location.hostname+(e.location.port?":"+e.location.port:"")};try{Object.defineProperty(e.location,"origin",{get:n,enumerable:!0})}catch(o){setInterval(function(){e.location.origin=n()},100)}}})(typeof global!="undefined"?global:typeof window!="undefined"?window:typeof self!="undefined"?self:Er)});var qr=Pt((Mt,Nr)=>{/*! + * clipboard.js v2.0.11 + * https://clipboardjs.com/ + * + * Licensed MIT © Zeno Rocha + */(function(t,r){typeof Mt=="object"&&typeof Nr=="object"?Nr.exports=r():typeof define=="function"&&define.amd?define([],r):typeof Mt=="object"?Mt.ClipboardJS=r():t.ClipboardJS=r()})(Mt,function(){return function(){var e={686:function(n,o,i){"use strict";i.d(o,{default:function(){return Ai}});var s=i(279),a=i.n(s),f=i(370),c=i.n(f),u=i(817),p=i.n(u);function m(j){try{return document.execCommand(j)}catch(T){return!1}}var d=function(T){var E=p()(T);return m("cut"),E},h=d;function v(j){var T=document.documentElement.getAttribute("dir")==="rtl",E=document.createElement("textarea");E.style.fontSize="12pt",E.style.border="0",E.style.padding="0",E.style.margin="0",E.style.position="absolute",E.style[T?"right":"left"]="-9999px";var H=window.pageYOffset||document.documentElement.scrollTop;return E.style.top="".concat(H,"px"),E.setAttribute("readonly",""),E.value=j,E}var Y=function(T,E){var H=v(T);E.container.appendChild(H);var I=p()(H);return m("copy"),H.remove(),I},B=function(T){var E=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{container:document.body},H="";return typeof T=="string"?H=Y(T,E):T instanceof HTMLInputElement&&!["text","search","url","tel","password"].includes(T==null?void 0:T.type)?H=Y(T.value,E):(H=p()(T),m("copy")),H},N=B;function O(j){return typeof Symbol=="function"&&typeof Symbol.iterator=="symbol"?O=function(E){return typeof E}:O=function(E){return E&&typeof Symbol=="function"&&E.constructor===Symbol&&E!==Symbol.prototype?"symbol":typeof E},O(j)}var Qe=function(){var T=arguments.length>0&&arguments[0]!==void 0?arguments[0]:{},E=T.action,H=E===void 0?"copy":E,I=T.container,q=T.target,Me=T.text;if(H!=="copy"&&H!=="cut")throw new Error('Invalid "action" value, use either "copy" or "cut"');if(q!==void 0)if(q&&O(q)==="object"&&q.nodeType===1){if(H==="copy"&&q.hasAttribute("disabled"))throw new Error('Invalid "target" attribute. Please use "readonly" instead of "disabled" attribute');if(H==="cut"&&(q.hasAttribute("readonly")||q.hasAttribute("disabled")))throw new Error(`Invalid "target" attribute. You can't cut text from elements with "readonly" or "disabled" attributes`)}else throw new Error('Invalid "target" value, use a valid Element');if(Me)return N(Me,{container:I});if(q)return H==="cut"?h(q):N(q,{container:I})},De=Qe;function $e(j){return typeof Symbol=="function"&&typeof Symbol.iterator=="symbol"?$e=function(E){return typeof E}:$e=function(E){return E&&typeof Symbol=="function"&&E.constructor===Symbol&&E!==Symbol.prototype?"symbol":typeof E},$e(j)}function Ei(j,T){if(!(j instanceof T))throw new TypeError("Cannot call a class as a function")}function tn(j,T){for(var E=0;E0&&arguments[0]!==void 0?arguments[0]:{};this.action=typeof I.action=="function"?I.action:this.defaultAction,this.target=typeof I.target=="function"?I.target:this.defaultTarget,this.text=typeof I.text=="function"?I.text:this.defaultText,this.container=$e(I.container)==="object"?I.container:document.body}},{key:"listenClick",value:function(I){var q=this;this.listener=c()(I,"click",function(Me){return q.onClick(Me)})}},{key:"onClick",value:function(I){var q=I.delegateTarget||I.currentTarget,Me=this.action(q)||"copy",kt=De({action:Me,container:this.container,target:this.target(q),text:this.text(q)});this.emit(kt?"success":"error",{action:Me,text:kt,trigger:q,clearSelection:function(){q&&q.focus(),window.getSelection().removeAllRanges()}})}},{key:"defaultAction",value:function(I){return vr("action",I)}},{key:"defaultTarget",value:function(I){var q=vr("target",I);if(q)return document.querySelector(q)}},{key:"defaultText",value:function(I){return vr("text",I)}},{key:"destroy",value:function(){this.listener.destroy()}}],[{key:"copy",value:function(I){var q=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{container:document.body};return N(I,q)}},{key:"cut",value:function(I){return h(I)}},{key:"isSupported",value:function(){var I=arguments.length>0&&arguments[0]!==void 0?arguments[0]:["copy","cut"],q=typeof I=="string"?[I]:I,Me=!!document.queryCommandSupported;return q.forEach(function(kt){Me=Me&&!!document.queryCommandSupported(kt)}),Me}}]),E}(a()),Ai=Li},828:function(n){var o=9;if(typeof Element!="undefined"&&!Element.prototype.matches){var i=Element.prototype;i.matches=i.matchesSelector||i.mozMatchesSelector||i.msMatchesSelector||i.oMatchesSelector||i.webkitMatchesSelector}function s(a,f){for(;a&&a.nodeType!==o;){if(typeof a.matches=="function"&&a.matches(f))return a;a=a.parentNode}}n.exports=s},438:function(n,o,i){var s=i(828);function a(u,p,m,d,h){var v=c.apply(this,arguments);return u.addEventListener(m,v,h),{destroy:function(){u.removeEventListener(m,v,h)}}}function f(u,p,m,d,h){return typeof u.addEventListener=="function"?a.apply(null,arguments):typeof m=="function"?a.bind(null,document).apply(null,arguments):(typeof u=="string"&&(u=document.querySelectorAll(u)),Array.prototype.map.call(u,function(v){return a(v,p,m,d,h)}))}function c(u,p,m,d){return function(h){h.delegateTarget=s(h.target,p),h.delegateTarget&&d.call(u,h)}}n.exports=f},879:function(n,o){o.node=function(i){return i!==void 0&&i instanceof HTMLElement&&i.nodeType===1},o.nodeList=function(i){var s=Object.prototype.toString.call(i);return i!==void 0&&(s==="[object NodeList]"||s==="[object HTMLCollection]")&&"length"in i&&(i.length===0||o.node(i[0]))},o.string=function(i){return typeof i=="string"||i instanceof String},o.fn=function(i){var s=Object.prototype.toString.call(i);return s==="[object Function]"}},370:function(n,o,i){var s=i(879),a=i(438);function f(m,d,h){if(!m&&!d&&!h)throw new Error("Missing required arguments");if(!s.string(d))throw new TypeError("Second argument must be a String");if(!s.fn(h))throw new TypeError("Third argument must be a Function");if(s.node(m))return c(m,d,h);if(s.nodeList(m))return u(m,d,h);if(s.string(m))return p(m,d,h);throw new TypeError("First argument must be a String, HTMLElement, HTMLCollection, or NodeList")}function c(m,d,h){return m.addEventListener(d,h),{destroy:function(){m.removeEventListener(d,h)}}}function u(m,d,h){return Array.prototype.forEach.call(m,function(v){v.addEventListener(d,h)}),{destroy:function(){Array.prototype.forEach.call(m,function(v){v.removeEventListener(d,h)})}}}function p(m,d,h){return a(document.body,m,d,h)}n.exports=f},817:function(n){function o(i){var s;if(i.nodeName==="SELECT")i.focus(),s=i.value;else if(i.nodeName==="INPUT"||i.nodeName==="TEXTAREA"){var a=i.hasAttribute("readonly");a||i.setAttribute("readonly",""),i.select(),i.setSelectionRange(0,i.value.length),a||i.removeAttribute("readonly"),s=i.value}else{i.hasAttribute("contenteditable")&&i.focus();var f=window.getSelection(),c=document.createRange();c.selectNodeContents(i),f.removeAllRanges(),f.addRange(c),s=f.toString()}return s}n.exports=o},279:function(n){function o(){}o.prototype={on:function(i,s,a){var f=this.e||(this.e={});return(f[i]||(f[i]=[])).push({fn:s,ctx:a}),this},once:function(i,s,a){var f=this;function c(){f.off(i,c),s.apply(a,arguments)}return c._=s,this.on(i,c,a)},emit:function(i){var s=[].slice.call(arguments,1),a=((this.e||(this.e={}))[i]||[]).slice(),f=0,c=a.length;for(f;f{"use strict";/*! + * escape-html + * Copyright(c) 2012-2013 TJ Holowaychuk + * Copyright(c) 2015 Andreas Lubbe + * Copyright(c) 2015 Tiancheng "Timothy" Gu + * MIT Licensed + */var rs=/["'&<>]/;Yo.exports=ns;function ns(e){var t=""+e,r=rs.exec(t);if(!r)return t;var n,o="",i=0,s=0;for(i=r.index;i0&&i[i.length-1])&&(c[0]===6||c[0]===2)){r=0;continue}if(c[0]===3&&(!i||c[1]>i[0]&&c[1]=e.length&&(e=void 0),{value:e&&e[n++],done:!e}}};throw new TypeError(t?"Object is not iterable.":"Symbol.iterator is not defined.")}function W(e,t){var r=typeof Symbol=="function"&&e[Symbol.iterator];if(!r)return e;var n=r.call(e),o,i=[],s;try{for(;(t===void 0||t-- >0)&&!(o=n.next()).done;)i.push(o.value)}catch(a){s={error:a}}finally{try{o&&!o.done&&(r=n.return)&&r.call(n)}finally{if(s)throw s.error}}return i}function D(e,t,r){if(r||arguments.length===2)for(var n=0,o=t.length,i;n1||a(m,d)})})}function a(m,d){try{f(n[m](d))}catch(h){p(i[0][3],h)}}function f(m){m.value instanceof et?Promise.resolve(m.value.v).then(c,u):p(i[0][2],m)}function c(m){a("next",m)}function u(m){a("throw",m)}function p(m,d){m(d),i.shift(),i.length&&a(i[0][0],i[0][1])}}function pn(e){if(!Symbol.asyncIterator)throw new TypeError("Symbol.asyncIterator is not defined.");var t=e[Symbol.asyncIterator],r;return t?t.call(e):(e=typeof Ee=="function"?Ee(e):e[Symbol.iterator](),r={},n("next"),n("throw"),n("return"),r[Symbol.asyncIterator]=function(){return this},r);function n(i){r[i]=e[i]&&function(s){return new Promise(function(a,f){s=e[i](s),o(a,f,s.done,s.value)})}}function o(i,s,a,f){Promise.resolve(f).then(function(c){i({value:c,done:a})},s)}}function C(e){return typeof e=="function"}function at(e){var t=function(n){Error.call(n),n.stack=new Error().stack},r=e(t);return r.prototype=Object.create(Error.prototype),r.prototype.constructor=r,r}var It=at(function(e){return function(r){e(this),this.message=r?r.length+` errors occurred during unsubscription: +`+r.map(function(n,o){return o+1+") "+n.toString()}).join(` + `):"",this.name="UnsubscriptionError",this.errors=r}});function Ve(e,t){if(e){var r=e.indexOf(t);0<=r&&e.splice(r,1)}}var Ie=function(){function e(t){this.initialTeardown=t,this.closed=!1,this._parentage=null,this._finalizers=null}return e.prototype.unsubscribe=function(){var t,r,n,o,i;if(!this.closed){this.closed=!0;var s=this._parentage;if(s)if(this._parentage=null,Array.isArray(s))try{for(var a=Ee(s),f=a.next();!f.done;f=a.next()){var c=f.value;c.remove(this)}}catch(v){t={error:v}}finally{try{f&&!f.done&&(r=a.return)&&r.call(a)}finally{if(t)throw t.error}}else s.remove(this);var u=this.initialTeardown;if(C(u))try{u()}catch(v){i=v instanceof It?v.errors:[v]}var p=this._finalizers;if(p){this._finalizers=null;try{for(var m=Ee(p),d=m.next();!d.done;d=m.next()){var h=d.value;try{ln(h)}catch(v){i=i!=null?i:[],v instanceof It?i=D(D([],W(i)),W(v.errors)):i.push(v)}}}catch(v){n={error:v}}finally{try{d&&!d.done&&(o=m.return)&&o.call(m)}finally{if(n)throw n.error}}}if(i)throw new It(i)}},e.prototype.add=function(t){var r;if(t&&t!==this)if(this.closed)ln(t);else{if(t instanceof e){if(t.closed||t._hasParent(this))return;t._addParent(this)}(this._finalizers=(r=this._finalizers)!==null&&r!==void 0?r:[]).push(t)}},e.prototype._hasParent=function(t){var r=this._parentage;return r===t||Array.isArray(r)&&r.includes(t)},e.prototype._addParent=function(t){var r=this._parentage;this._parentage=Array.isArray(r)?(r.push(t),r):r?[r,t]:t},e.prototype._removeParent=function(t){var r=this._parentage;r===t?this._parentage=null:Array.isArray(r)&&Ve(r,t)},e.prototype.remove=function(t){var r=this._finalizers;r&&Ve(r,t),t instanceof e&&t._removeParent(this)},e.EMPTY=function(){var t=new e;return t.closed=!0,t}(),e}();var Sr=Ie.EMPTY;function jt(e){return e instanceof Ie||e&&"closed"in e&&C(e.remove)&&C(e.add)&&C(e.unsubscribe)}function ln(e){C(e)?e():e.unsubscribe()}var Le={onUnhandledError:null,onStoppedNotification:null,Promise:void 0,useDeprecatedSynchronousErrorHandling:!1,useDeprecatedNextContext:!1};var st={setTimeout:function(e,t){for(var r=[],n=2;n0},enumerable:!1,configurable:!0}),t.prototype._trySubscribe=function(r){return this._throwIfClosed(),e.prototype._trySubscribe.call(this,r)},t.prototype._subscribe=function(r){return this._throwIfClosed(),this._checkFinalizedStatuses(r),this._innerSubscribe(r)},t.prototype._innerSubscribe=function(r){var n=this,o=this,i=o.hasError,s=o.isStopped,a=o.observers;return i||s?Sr:(this.currentObservers=null,a.push(r),new Ie(function(){n.currentObservers=null,Ve(a,r)}))},t.prototype._checkFinalizedStatuses=function(r){var n=this,o=n.hasError,i=n.thrownError,s=n.isStopped;o?r.error(i):s&&r.complete()},t.prototype.asObservable=function(){var r=new F;return r.source=this,r},t.create=function(r,n){return new xn(r,n)},t}(F);var xn=function(e){ie(t,e);function t(r,n){var o=e.call(this)||this;return o.destination=r,o.source=n,o}return t.prototype.next=function(r){var n,o;(o=(n=this.destination)===null||n===void 0?void 0:n.next)===null||o===void 0||o.call(n,r)},t.prototype.error=function(r){var n,o;(o=(n=this.destination)===null||n===void 0?void 0:n.error)===null||o===void 0||o.call(n,r)},t.prototype.complete=function(){var r,n;(n=(r=this.destination)===null||r===void 0?void 0:r.complete)===null||n===void 0||n.call(r)},t.prototype._subscribe=function(r){var n,o;return(o=(n=this.source)===null||n===void 0?void 0:n.subscribe(r))!==null&&o!==void 0?o:Sr},t}(x);var Et={now:function(){return(Et.delegate||Date).now()},delegate:void 0};var wt=function(e){ie(t,e);function t(r,n,o){r===void 0&&(r=1/0),n===void 0&&(n=1/0),o===void 0&&(o=Et);var i=e.call(this)||this;return i._bufferSize=r,i._windowTime=n,i._timestampProvider=o,i._buffer=[],i._infiniteTimeWindow=!0,i._infiniteTimeWindow=n===1/0,i._bufferSize=Math.max(1,r),i._windowTime=Math.max(1,n),i}return t.prototype.next=function(r){var n=this,o=n.isStopped,i=n._buffer,s=n._infiniteTimeWindow,a=n._timestampProvider,f=n._windowTime;o||(i.push(r),!s&&i.push(a.now()+f)),this._trimBuffer(),e.prototype.next.call(this,r)},t.prototype._subscribe=function(r){this._throwIfClosed(),this._trimBuffer();for(var n=this._innerSubscribe(r),o=this,i=o._infiniteTimeWindow,s=o._buffer,a=s.slice(),f=0;f0?e.prototype.requestAsyncId.call(this,r,n,o):(r.actions.push(this),r._scheduled||(r._scheduled=ut.requestAnimationFrame(function(){return r.flush(void 0)})))},t.prototype.recycleAsyncId=function(r,n,o){var i;if(o===void 0&&(o=0),o!=null?o>0:this.delay>0)return e.prototype.recycleAsyncId.call(this,r,n,o);var s=r.actions;n!=null&&((i=s[s.length-1])===null||i===void 0?void 0:i.id)!==n&&(ut.cancelAnimationFrame(n),r._scheduled=void 0)},t}(Wt);var Sn=function(e){ie(t,e);function t(){return e!==null&&e.apply(this,arguments)||this}return t.prototype.flush=function(r){this._active=!0;var n=this._scheduled;this._scheduled=void 0;var o=this.actions,i;r=r||o.shift();do if(i=r.execute(r.state,r.delay))break;while((r=o[0])&&r.id===n&&o.shift());if(this._active=!1,i){for(;(r=o[0])&&r.id===n&&o.shift();)r.unsubscribe();throw i}},t}(Dt);var Oe=new Sn(wn);var _=new F(function(e){return e.complete()});function Vt(e){return e&&C(e.schedule)}function Cr(e){return e[e.length-1]}function Ye(e){return C(Cr(e))?e.pop():void 0}function Te(e){return Vt(Cr(e))?e.pop():void 0}function zt(e,t){return typeof Cr(e)=="number"?e.pop():t}var pt=function(e){return e&&typeof e.length=="number"&&typeof e!="function"};function Nt(e){return C(e==null?void 0:e.then)}function qt(e){return C(e[ft])}function Kt(e){return Symbol.asyncIterator&&C(e==null?void 0:e[Symbol.asyncIterator])}function Qt(e){return new TypeError("You provided "+(e!==null&&typeof e=="object"?"an invalid object":"'"+e+"'")+" where a stream was expected. You can provide an Observable, Promise, ReadableStream, Array, AsyncIterable, or Iterable.")}function zi(){return typeof Symbol!="function"||!Symbol.iterator?"@@iterator":Symbol.iterator}var Yt=zi();function Gt(e){return C(e==null?void 0:e[Yt])}function Bt(e){return un(this,arguments,function(){var r,n,o,i;return $t(this,function(s){switch(s.label){case 0:r=e.getReader(),s.label=1;case 1:s.trys.push([1,,9,10]),s.label=2;case 2:return[4,et(r.read())];case 3:return n=s.sent(),o=n.value,i=n.done,i?[4,et(void 0)]:[3,5];case 4:return[2,s.sent()];case 5:return[4,et(o)];case 6:return[4,s.sent()];case 7:return s.sent(),[3,2];case 8:return[3,10];case 9:return r.releaseLock(),[7];case 10:return[2]}})})}function Jt(e){return C(e==null?void 0:e.getReader)}function U(e){if(e instanceof F)return e;if(e!=null){if(qt(e))return Ni(e);if(pt(e))return qi(e);if(Nt(e))return Ki(e);if(Kt(e))return On(e);if(Gt(e))return Qi(e);if(Jt(e))return Yi(e)}throw Qt(e)}function Ni(e){return new F(function(t){var r=e[ft]();if(C(r.subscribe))return r.subscribe(t);throw new TypeError("Provided object does not correctly implement Symbol.observable")})}function qi(e){return new F(function(t){for(var r=0;r=2;return function(n){return n.pipe(e?A(function(o,i){return e(o,i,n)}):de,ge(1),r?He(t):Dn(function(){return new Zt}))}}function Vn(){for(var e=[],t=0;t=2,!0))}function pe(e){e===void 0&&(e={});var t=e.connector,r=t===void 0?function(){return new x}:t,n=e.resetOnError,o=n===void 0?!0:n,i=e.resetOnComplete,s=i===void 0?!0:i,a=e.resetOnRefCountZero,f=a===void 0?!0:a;return function(c){var u,p,m,d=0,h=!1,v=!1,Y=function(){p==null||p.unsubscribe(),p=void 0},B=function(){Y(),u=m=void 0,h=v=!1},N=function(){var O=u;B(),O==null||O.unsubscribe()};return y(function(O,Qe){d++,!v&&!h&&Y();var De=m=m!=null?m:r();Qe.add(function(){d--,d===0&&!v&&!h&&(p=$r(N,f))}),De.subscribe(Qe),!u&&d>0&&(u=new rt({next:function($e){return De.next($e)},error:function($e){v=!0,Y(),p=$r(B,o,$e),De.error($e)},complete:function(){h=!0,Y(),p=$r(B,s),De.complete()}}),U(O).subscribe(u))})(c)}}function $r(e,t){for(var r=[],n=2;ne.next(document)),e}function K(e,t=document){return Array.from(t.querySelectorAll(e))}function z(e,t=document){let r=ce(e,t);if(typeof r=="undefined")throw new ReferenceError(`Missing element: expected "${e}" to be present`);return r}function ce(e,t=document){return t.querySelector(e)||void 0}function _e(){return document.activeElement instanceof HTMLElement&&document.activeElement||void 0}function tr(e){return L(b(document.body,"focusin"),b(document.body,"focusout")).pipe(ke(1),l(()=>{let t=_e();return typeof t!="undefined"?e.contains(t):!1}),V(e===_e()),J())}function Xe(e){return{x:e.offsetLeft,y:e.offsetTop}}function Kn(e){return L(b(window,"load"),b(window,"resize")).pipe(Ce(0,Oe),l(()=>Xe(e)),V(Xe(e)))}function rr(e){return{x:e.scrollLeft,y:e.scrollTop}}function dt(e){return L(b(e,"scroll"),b(window,"resize")).pipe(Ce(0,Oe),l(()=>rr(e)),V(rr(e)))}var Yn=function(){if(typeof Map!="undefined")return Map;function e(t,r){var n=-1;return t.some(function(o,i){return o[0]===r?(n=i,!0):!1}),n}return function(){function t(){this.__entries__=[]}return Object.defineProperty(t.prototype,"size",{get:function(){return this.__entries__.length},enumerable:!0,configurable:!0}),t.prototype.get=function(r){var n=e(this.__entries__,r),o=this.__entries__[n];return o&&o[1]},t.prototype.set=function(r,n){var o=e(this.__entries__,r);~o?this.__entries__[o][1]=n:this.__entries__.push([r,n])},t.prototype.delete=function(r){var n=this.__entries__,o=e(n,r);~o&&n.splice(o,1)},t.prototype.has=function(r){return!!~e(this.__entries__,r)},t.prototype.clear=function(){this.__entries__.splice(0)},t.prototype.forEach=function(r,n){n===void 0&&(n=null);for(var o=0,i=this.__entries__;o0},e.prototype.connect_=function(){!Wr||this.connected_||(document.addEventListener("transitionend",this.onTransitionEnd_),window.addEventListener("resize",this.refresh),va?(this.mutationsObserver_=new MutationObserver(this.refresh),this.mutationsObserver_.observe(document,{attributes:!0,childList:!0,characterData:!0,subtree:!0})):(document.addEventListener("DOMSubtreeModified",this.refresh),this.mutationEventsAdded_=!0),this.connected_=!0)},e.prototype.disconnect_=function(){!Wr||!this.connected_||(document.removeEventListener("transitionend",this.onTransitionEnd_),window.removeEventListener("resize",this.refresh),this.mutationsObserver_&&this.mutationsObserver_.disconnect(),this.mutationEventsAdded_&&document.removeEventListener("DOMSubtreeModified",this.refresh),this.mutationsObserver_=null,this.mutationEventsAdded_=!1,this.connected_=!1)},e.prototype.onTransitionEnd_=function(t){var r=t.propertyName,n=r===void 0?"":r,o=ba.some(function(i){return!!~n.indexOf(i)});o&&this.refresh()},e.getInstance=function(){return this.instance_||(this.instance_=new e),this.instance_},e.instance_=null,e}(),Gn=function(e,t){for(var r=0,n=Object.keys(t);r0},e}(),Jn=typeof WeakMap!="undefined"?new WeakMap:new Yn,Xn=function(){function e(t){if(!(this instanceof e))throw new TypeError("Cannot call a class as a function.");if(!arguments.length)throw new TypeError("1 argument required, but only 0 present.");var r=ga.getInstance(),n=new La(t,r,this);Jn.set(this,n)}return e}();["observe","unobserve","disconnect"].forEach(function(e){Xn.prototype[e]=function(){var t;return(t=Jn.get(this))[e].apply(t,arguments)}});var Aa=function(){return typeof nr.ResizeObserver!="undefined"?nr.ResizeObserver:Xn}(),Zn=Aa;var eo=new x,Ca=$(()=>k(new Zn(e=>{for(let t of e)eo.next(t)}))).pipe(g(e=>L(ze,k(e)).pipe(R(()=>e.disconnect()))),X(1));function he(e){return{width:e.offsetWidth,height:e.offsetHeight}}function ye(e){return Ca.pipe(S(t=>t.observe(e)),g(t=>eo.pipe(A(({target:r})=>r===e),R(()=>t.unobserve(e)),l(()=>he(e)))),V(he(e)))}function bt(e){return{width:e.scrollWidth,height:e.scrollHeight}}function ar(e){let t=e.parentElement;for(;t&&(e.scrollWidth<=t.scrollWidth&&e.scrollHeight<=t.scrollHeight);)t=(e=t).parentElement;return t?e:void 0}var to=new x,Ra=$(()=>k(new IntersectionObserver(e=>{for(let t of e)to.next(t)},{threshold:0}))).pipe(g(e=>L(ze,k(e)).pipe(R(()=>e.disconnect()))),X(1));function sr(e){return Ra.pipe(S(t=>t.observe(e)),g(t=>to.pipe(A(({target:r})=>r===e),R(()=>t.unobserve(e)),l(({isIntersecting:r})=>r))))}function ro(e,t=16){return dt(e).pipe(l(({y:r})=>{let n=he(e),o=bt(e);return r>=o.height-n.height-t}),J())}var cr={drawer:z("[data-md-toggle=drawer]"),search:z("[data-md-toggle=search]")};function no(e){return cr[e].checked}function Ke(e,t){cr[e].checked!==t&&cr[e].click()}function Ue(e){let t=cr[e];return b(t,"change").pipe(l(()=>t.checked),V(t.checked))}function ka(e,t){switch(e.constructor){case HTMLInputElement:return e.type==="radio"?/^Arrow/.test(t):!0;case HTMLSelectElement:case HTMLTextAreaElement:return!0;default:return e.isContentEditable}}function Ha(){return L(b(window,"compositionstart").pipe(l(()=>!0)),b(window,"compositionend").pipe(l(()=>!1))).pipe(V(!1))}function oo(){let e=b(window,"keydown").pipe(A(t=>!(t.metaKey||t.ctrlKey)),l(t=>({mode:no("search")?"search":"global",type:t.key,claim(){t.preventDefault(),t.stopPropagation()}})),A(({mode:t,type:r})=>{if(t==="global"){let n=_e();if(typeof n!="undefined")return!ka(n,r)}return!0}),pe());return Ha().pipe(g(t=>t?_:e))}function le(){return new URL(location.href)}function ot(e){location.href=e.href}function io(){return new x}function ao(e,t){if(typeof t=="string"||typeof t=="number")e.innerHTML+=t.toString();else if(t instanceof Node)e.appendChild(t);else if(Array.isArray(t))for(let r of t)ao(e,r)}function M(e,t,...r){let n=document.createElement(e);if(t)for(let o of Object.keys(t))typeof t[o]!="undefined"&&(typeof t[o]!="boolean"?n.setAttribute(o,t[o]):n.setAttribute(o,""));for(let o of r)ao(n,o);return n}function fr(e){if(e>999){let t=+((e-950)%1e3>99);return`${((e+1e-6)/1e3).toFixed(t)}k`}else return e.toString()}function so(){return location.hash.substring(1)}function Dr(e){let t=M("a",{href:e});t.addEventListener("click",r=>r.stopPropagation()),t.click()}function Pa(e){return L(b(window,"hashchange"),e).pipe(l(so),V(so()),A(t=>t.length>0),X(1))}function co(e){return Pa(e).pipe(l(t=>ce(`[id="${t}"]`)),A(t=>typeof t!="undefined"))}function Vr(e){let t=matchMedia(e);return er(r=>t.addListener(()=>r(t.matches))).pipe(V(t.matches))}function fo(){let e=matchMedia("print");return L(b(window,"beforeprint").pipe(l(()=>!0)),b(window,"afterprint").pipe(l(()=>!1))).pipe(V(e.matches))}function zr(e,t){return e.pipe(g(r=>r?t():_))}function ur(e,t={credentials:"same-origin"}){return ue(fetch(`${e}`,t)).pipe(fe(()=>_),g(r=>r.status!==200?Ot(()=>new Error(r.statusText)):k(r)))}function We(e,t){return ur(e,t).pipe(g(r=>r.json()),X(1))}function uo(e,t){let r=new DOMParser;return ur(e,t).pipe(g(n=>n.text()),l(n=>r.parseFromString(n,"text/xml")),X(1))}function pr(e){let t=M("script",{src:e});return $(()=>(document.head.appendChild(t),L(b(t,"load"),b(t,"error").pipe(g(()=>Ot(()=>new ReferenceError(`Invalid script: ${e}`))))).pipe(l(()=>{}),R(()=>document.head.removeChild(t)),ge(1))))}function po(){return{x:Math.max(0,scrollX),y:Math.max(0,scrollY)}}function lo(){return L(b(window,"scroll",{passive:!0}),b(window,"resize",{passive:!0})).pipe(l(po),V(po()))}function mo(){return{width:innerWidth,height:innerHeight}}function ho(){return b(window,"resize",{passive:!0}).pipe(l(mo),V(mo()))}function bo(){return G([lo(),ho()]).pipe(l(([e,t])=>({offset:e,size:t})),X(1))}function lr(e,{viewport$:t,header$:r}){let n=t.pipe(ee("size")),o=G([n,r]).pipe(l(()=>Xe(e)));return G([r,t,o]).pipe(l(([{height:i},{offset:s,size:a},{x:f,y:c}])=>({offset:{x:s.x-f,y:s.y-c+i},size:a})))}(()=>{function e(n,o){parent.postMessage(n,o||"*")}function t(...n){return n.reduce((o,i)=>o.then(()=>new Promise(s=>{let a=document.createElement("script");a.src=i,a.onload=s,document.body.appendChild(a)})),Promise.resolve())}var r=class extends EventTarget{constructor(n){super(),this.url=n,this.m=i=>{i.source===this.w&&(this.dispatchEvent(new MessageEvent("message",{data:i.data})),this.onmessage&&this.onmessage(i))},this.e=(i,s,a,f,c)=>{if(s===`${this.url}`){let u=new ErrorEvent("error",{message:i,filename:s,lineno:a,colno:f,error:c});this.dispatchEvent(u),this.onerror&&this.onerror(u)}};let o=document.createElement("iframe");o.hidden=!0,document.body.appendChild(this.iframe=o),this.w.document.open(),this.w.document.write(` + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + + +
+
+
+ + + + +
+
+ + + + + + + + + + + + +

Changelog

+

Here you can find all the released changes to Rye. If you want to also see +the in-development changes that were not released yet, refer to the +CHANGELOG.md file +in the repository.

+ + +

0.17.0

+

Released on 2024-01-15

+
    +
  • +

    Fixed default generated script reference. #527

    +
  • +
  • +

    Correctly fall back to home folder if HOME is unset. #533

    +
  • +
+

0.16.0

+

Released on 2023-12-17

+
    +
  • +

    By default a script with the name of the project is now also configured. #519

    +
  • +
  • +

    Rye now configures hatchling better in rye init so that it works with + hatchling 1.19 and later. #521

    +
  • +
  • +

    Rye now detects the dummy Python shim that starts the windows store and + refuses to consider it. #486

    +
  • +
+

0.15.2

+

Released on 2023-10-04

+
    +
  • Fixed the updater not replacing the python shim correctly on Linux.
  • +
+

0.15.1

+

Released on 2023-10-03

+
    +
  • Fixed the updater not replacing the python3 shim correctly.
  • +
+

0.15.0

+

Released on 2023-10-03

+
    +
  • Added support for Python 3.12. #462
  • +
+

0.14.0

+

Released on 2023-10-01

+
    +
  • +

    Add support for fetching alternative CPU architectures. #447

    +
  • +
  • +

    The order of git submodule initialization was changed. This improves the + automatic author detection when includeIf is used. #443

    +
  • +
  • +

    The linux shim installer code will no longer fall back to symlinks when a + hardlink cannot be created. This is done as a symlinked shim will not + ever function correctly on Linux. This prevents the shim executables like + python to instead act as if they are rye. The fallback behavior is now + to copy the executable instead. #441

    +
  • +
  • +

    The installer now detects fish and will spit out additional instructions + for configuring the shell.

    +
  • +
  • +

    Fix the wrong behavior when bump version. #454

    +
  • +
+

0.13.0

+

Released on 2023-08-29

+
    +
  • +

    Add a python3 shim on windows. Previously entering python3 in the + command line would always bring up the windows store python proxy even + when global shims were enabled. As virtualenvs do not support the + python3 executable on windows, the internal shim handling is now also + changed so that trying to launch python3 will fall back to python. + This makes it possible to run maturin build.

    +
  • +
  • +

    Add maturin build command to start a new maturin PyO3 project.

    +
  • +
+

0.12.0

+

Released on 2023-08-27

+
    +
  • +

    Improve handling of the pth files for TCL on pypy. #409

    +
  • +
  • +

    The rye tools list command now accepts -v to also print out the + versions of the installed tools. #396

    +
  • +
  • +

    Fixed parsing of versions by rye version. #397

    +
  • +
  • +

    Improved the help message for rye init. #401

    +
  • +
  • +

    The email address now defaults to a syntactically valid email address + if not known to prevent errors with some build tools.

    +
  • +
  • +

    Added new Python versions.

    +
  • +
  • +

    The rye installer now detects NOEXEC temporary folders and prints out + a more helpful error message. #394

    +
  • +
  • +

    Fixed an issue where the author email was incorrectly detected. #382

    +
  • +
  • +

    The prompt of new virtualenvs is now set to the project name. #383

    +
  • +
+

0.11.0

+

Released on 2023-07-18

+
    +
  • +

    Added new Python versions.

    +
  • +
  • +

    Added a new config key default.author to configure the default author + that should be set. This overrides the default author that is normally + loaded from the git config. #377

    +
  • +
  • +

    When importing with rye init and no src folder exists, it will not be + created. #375

    +
  • +
  • +

    Added support for shell command on Windows. #363

    +
  • +
  • +

    Pin down pip to an older version to avoid issues with an incompatible + pip-tools version. This does not yet update pip-tools to 7.0 as there + are significant regressions in 7.x. #374

    +
  • +
  • +

    The version command can show dynamic versions now. #355

    +
  • +
  • +

    rye add now properly checks some incompatible argument combinations. #347

    +
  • +
  • +

    There is now more toolchain validation. This better supports cases where + rye was interrupted during sync. #351

    +
  • +
+

0.10.0

+

Released on 2023-07-07

+
    +
  • +

    Fixed a bug with rye init not operating correctly due to a argument conflict. #346

    +
  • +
  • +

    Scripts now support a PDM style call script type. #345

    +
  • +
  • +

    The init command is now capable of importing existing projects. #265

    +
  • +
  • +

    Fixed the global shim behavior on Windows. #344

    +
  • +
+

0.9.0

+

Released on 2023-06-21

+
    +
  • +

    The internal Rye Python version is now 3.11.

    +
  • +
  • +

    Rye now emits most messages, most of the time to stdout rather than stderr. #342

    +
  • +
  • +

    rye add now accepts --pin to let one override the type of pin to use. #341

    +
  • +
  • +

    Added rye config to read and manipulate the config.toml file. #339

    +
  • +
  • +

    Added support for the new behavior.global-python flag which turns on global + Python shimming. When enabled then the python shim works even outside of + Rye managed projects. Additionally the shim (when run outside of Rye managed + projects) supports a special first parameter +VERSION which requests a + specific version of Python (eg: python +3.8 to request Python 3.8). #336

    +
  • +
  • +

    Renamed the config key default.dependency_operator to default.dependency-operator + and behavior.force_rye_managed to behavior.force-rye-managed. #338

    +
  • +
+

0.8.0

+

Released on 2023-06-18

+
    +
  • +

    Rye for now prefers >= over ~= for newly added dependencies.

    +
  • +
  • +

    The workspace member declaration is now platform independent. If members is + now explicitly set to an empty list it will not fall back to auto discovery. #331

    +
  • +
  • +

    rye add now pins versions with == instead of ~= when the version of the + package does not use at least two components. This means that for instance it + will now correctly use openai-whisper==20230314 rather than + openai-whisper~=20230314 which is not actually satisfiable. #328

    +
  • +
  • +

    rye install now lets you install dependencies into the tool's virtualenv + during installation that are undeclared via the new --extra-requirement + option. #326

    +
  • +
  • +

    Improved handling of relative path installations by setting PROJECT_ROOT + the same way as PDM does. #321

    +
  • +
  • +

    Workspaces will now never discover pyproject.toml files in any dot + directories. (Name starting with .) #329

    +
  • +
  • +

    Fixed rye build not working correctly on Windows. #327

    +
  • +
+

0.7.0

+

Released on 2023-06-12

+
    +
  • +

    rye sync and rye lock now accept --pyproject. #296

    +
  • +
  • +

    Added JSON output to rye toolchain list by adding --format=json. #306

    +
  • +
  • +

    rye version can bump version by --bump option now. #298

    +
  • +
  • +

    Fixed members not handled correctly in workspaces. #300

    +
  • +
  • +

    Add --clean for build command. #297

    +
  • +
  • +

    Fixed an issue where pip was not invoked from the right working directory + causing issues for workspace installations. #292

    +
  • +
  • +

    rye init now accepts --private to set the Private :: Do Not Upload classifier + that prevents uploads to PyPI. #291

    +
  • +
+

0.6.0

+

Released on 2023-06-03

+
    +
  • +

    Add version subcommand for rye. #285

    +
  • +
  • +

    Fixed rye pin pinning the wrong version. #288

    +
  • +
  • +

    Calling rye init on the root directory no longer fails. #274

    +
  • +
  • +

    rye run, show, pin, shell and build now take a --pyproject + argument. #232

    +
  • +
+

0.5.0

+

Released on 2023-05-31

+
    +
  • +

    Rye will no longer enforce a downloaded interpreter for the internal + toolchain. If one has been registered that is compatible it will be + used. Additionally the installer now supports the RYE_TOOLCHAIN + environment variable which allows a user to supply an already existing + Python interpreter at install time. #267

    +
  • +
  • +

    The publish command now supports --yes to disable prompts. #270

    +
  • +
  • +

    When a Python debug build (Py_DEBUG) is registered as custom toolchain, + -dbg is automatically appended to the name by default. #269

    +
  • +
  • +

    lto+pgo builds are now preferred for the Python toolchain builds when + available. #268

    +
  • +
  • +

    It's now possible for .python-version to request partial Python versions + in which case the latest available is used. In particular this means that + a version like 3.10 can be written into .python-version rather than + 3.10.11. This can be accomplished by invoking pin with the new + --relaxed flag. #255

    +
  • +
  • +

    Workspaces will no longer discover pyproject.toml files in virtualenvs + or .git folders. #266

    +
  • +
  • +

    Adding or removing dependencies with add or remove now reformats + the dependencies array in the pyproject.toml file to multi-line + with trailing commas. This should result in significantly better + diffing behavior out of the box. #263

    +
  • +
  • +

    Default build-system and license can be specified in global config. #244

    +
  • +
  • +

    Fixed an issue where the init command would not let you create + flit based projects. #254

    +
  • +
  • +

    Resolve an error ("No such file or directory") shown after updates on + Linux machines. #252

    +
  • +
  • +

    The built-in updater now validates checksums of updates when updates have + SHA-256 hashes available. #253

    +
  • +
  • +

    init now accepts --no-pin to not create a .python-version file. #247

    +
  • +
+

0.4.0

+

Released on 2023-05-29

+
    +
  • +

    Releases starting with 0.4.0 onwards are published with SHA256 checksum + files for all release assets. These files are not yet validated by the + installer or updater however.

    +
  • +
  • +

    The install command can now install tools from custom indexes. #240

    +
  • +
  • +

    Virtualenvs on Unix are now created with a hack to pre-configure TCL and + TKinter. #233

    +
  • +
  • +

    Fix invalid version error when using rye init with custom toolchain. #234

    +
  • +
  • +

    Failed tool installations now properly clean up. #225

    +
  • +
  • +

    Correctly swap the rye executable on windows when performing an update + to a git version via self update.

    +
  • +
+

0.3.0

+

Released on 2023-05-27

+
    +
  • +

    Support retrieving username and repository-url from credentials if not + provided for the publish command. #217

    +
  • +
  • +

    The installer now validates the availability of shared libraries + on Linux with ldd and emits an error with additional information + if necessary shared libraries are missing. #220

    +
  • +
  • +

    It's now possible to configure http and https proxies. #215

    +
  • +
  • +

    If a package is not found because it only has matching pre-releases, + a warning is now printed to tell the user to pass --pre. #218

    +
  • +
  • +

    Add --username parameter for rye publish. #211

    +
  • +
  • +

    The shims are now more resilient. Previously a pyproject.toml file + caused in all cases a virtualenv to be created. Now this will only + happen when the rye.tool.managed flag is set to true. The old + behavior can be forced via the global config. #212

    +
  • +
+

0.2.0

+

Released on 2023-05-23

+
    +
  • +

    Resolved a bug where on Windows hitting the shift key (or some other keys) + in confirm prompts would cause an error.

    +
  • +
  • +

    The installer on Windows now warns if symlinks are not enabled and directs + the user to enable developer mode. The --version output now also + shows if symlinks are available. #205

    +
  • +
  • +

    Support auto fix requires-python when there is a conflict. #160

    +
  • +
  • +

    Added support for custom indexes. #199

    +
  • +
  • +

    rye add no longer complains when a local version information is + in the version. #199

    +
  • +
+

0.1.2

+

Released on 2023-05-22

+
    +
  • +

    Fixed dev-dependencies not being installed when using workspace. #170

    +
  • +
  • +

    init no longer creates invalid flit config. #195

    +
  • +
  • +

    Support direct references when adding a package. #158

    +
  • +
  • +

    Fixed a bug with uninstall on Unix platforms. #197

    +
  • +
+

0.1.1

+

Released on 2023-05-18

+
    +
  • +

    The installer on windows will now ask for a key to be pressed so it does + not close the window without information. #183

    +
  • +
  • +

    Fixed an issue on macOS where the installer would die with "os error 24" + when directly piped to bash. #184

    +
  • +
+

0.1.0

+

Released on 2023-05-17

+
    +
  • +

    Rye now comes with binary releases for some platforms.

    +
  • +
  • +

    A new self uninstall command was added to uninstall rye and the new + self update command updates to the latest release version.

    +
  • +
  • +

    Rye now includes a publish command for publishing Python packages to a + package repository. #86

    +
  • +
  • +

    Script declarations in pyproject.toml now permit chaining and custom + environment variables. #153

    +
  • +
  • +

    Added tools install and tools uninstall as aliases for install and + uninstall and added tools list to show all installed tools.

    +
  • +
  • +

    Rye is now capable of downloading a selected set of PyPy releases. To do + so use rye pin pypy@3.9.16 or any other supported PyPy release.

    +
  • +
  • +

    Custom cpython toolchains are now registered just as cpython rather + than custom-cpython.

    +
  • +
  • +

    Rye now supports Python down to 3.7.

    +
  • +
  • +

    Rye's self command now includes a completion subcommand to generate + a completion script for your shell.

    +
  • +
  • +

    The downloaded Python distributions are now validated against the + SHA-256 hashes.

    +
  • +
  • +

    Rye now builds on windows. This is even more experimental though + than support for Linux and macOS.

    +
  • +
  • +

    Added --features and --all-features for lock and sync.

    +
  • +
  • +

    Rye will now look at the RYE_HOME to determine the location of the + .rye folder. If it's not set, $HOME/.rye is used as before.

    +
  • +
  • +

    Rye now has a most consistent handling for virtualenv versions. If + .python-version is provided, that version is used. Otherwise if + requires-python is set in the pyproject.toml, that version is used + instead. When a new project is created the .python-version file is + written and the current latest cpython version is picked.

    +
  • +
  • +

    It's now possible to explicitly set the name of the project when + initializing a new one.

    +
  • +
  • +

    Rye's init command now attempts to initialize projects with git and + will automatically create a src/project_name/__init__.py file.

    +
  • +
  • +

    Rye can now also generate a license text when initializing projects.

    +
  • +
  • +

    Rye now supports negative (exclusion) dependencies. These can be used to + prevent a dependency from installing, even if something else in the graph + depends on it. Use rye add --exclude package-name to add such a dependency.

    +
  • +
  • +

    sync now accepts --no-lock to prevent updating the lock file.

    +
  • +
  • +

    Rye's add command now accepts a --pre parameter to include pre-release.

    +
  • +
  • +

    Rye's pin command now updates the pyproject.toml requires-python.

    +
  • +
  • +

    Rye's install command now accepts a --include-dep parameter to include + scripts from one or more given dependencies.

    +
  • +
  • +

    Rye now honors requires-python in the add command. This means the the + initial resolution will not pick a version higher than what's supported by + the lower boundary.

    +
  • +
  • +

    When installing packages as global tools, a warning is now emitted if there + were no scripts in the package. Additionally installing packages from local + paths and zip files is now supported.

    +
  • +
  • +

    A rye self update command was added to compile and install the latest + version via cargo.

    +
  • +
  • +

    Added more convenient ways to install from git/urls by supplying a --git + or --url parameter. This will behind the scenes format a PEP 508 requirement + string.

    +
  • +
  • +

    Added a shell command which will spawn a shell with the virtualenv activated.

    +
  • +
  • +

    Added a make-req command to conveniently format out PEP 508 requirement + strings from parts.

    +
  • +
  • +

    The internal virtualenv used to manage pip-tools and other libraries now + automatically updates when necessary.

    +
  • +
  • +

    rye toolchain register can now be used to register a local python installation + as toolchain with rye.

    +
  • +
  • +

    rye build was added to allow building sdist and bdist_wheel distributions.

    +
  • +
  • +

    Rye now correctly handles whitespace in folder names.

    +
  • +
+ + + + + + + +
+
+ + + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/community/index.html b/community/index.html new file mode 100644 index 0000000000..ca1c548617 --- /dev/null +++ b/community/index.html @@ -0,0 +1,866 @@ + + + + + + + + + + + + + + + + + + + + + + + + Community - Rye + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + + + +
+
+ + + + + + + + + + +
+
+ + + + + + + + + + + + +

Community

+

Rye is a new project and feedback is greatly appreciated. Lots of it. Because +of this there are various different ways in which you can engage with either +the developer or other members of the community:

+ +

You can also reach out via Twitter or +Bluesky.

+ + + + + + + + +
+
+ + + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/get b/get new file mode 100755 index 0000000000..ba6eadb06a --- /dev/null +++ b/get @@ -0,0 +1,82 @@ +#!/usr/bin/env bash +set -euo pipefail + +# Wrap everything in a function so that a truncated script +# does not have the chance to cause issues. +__wrap__() { + +# allow overriding the version +VERSION=${RYE_VERSION:-latest} +# allow overriding the install option +INSTALL_OPTION=${RYE_INSTALL_OPTION:-""} + +REPO=mitsuhiko/rye +PLATFORM=`uname -s` +ARCH=`uname -m` + +if [[ $PLATFORM == "Darwin" ]]; then + PLATFORM="macos" +elif [[ $PLATFORM == "Linux" ]]; then + PLATFORM="linux" +fi + +if [[ $ARCH == armv8* ]] || [[ $ARCH == arm64* ]] || [[ $ARCH == aarch64* ]]; then + ARCH="aarch64" +elif [[ $ARCH == i686* ]]; then + ARCH="x86" +fi + +BINARY="rye-${ARCH}-${PLATFORM}" + +# Oddly enough GitHub has different URLs for latest vs specific version +if [[ $VERSION == "latest" ]]; then + DOWNLOAD_URL=https://github.com/${REPO}/releases/latest/download/${BINARY}.gz +else + DOWNLOAD_URL=https://github.com/${REPO}/releases/download/${VERSION}/${BINARY}.gz +fi + +echo "This script will automatically download and install rye (${VERSION}) for you." +if [ "x$(id -u)" == "x0" ]; then + echo "warning: this script is running as root. This is dangerous and unnecessary!" +fi + +if ! hash curl 2> /dev/null; then + echo "error: you do not have 'curl' installed which is required for this script." + exit 1 +fi + +if ! hash gunzip 2> /dev/null; then + echo "error: you do not have 'gunzip' installed which is required for this script." + exit 1 +fi + +TEMP_FILE=`mktemp "${TMPDIR:-/tmp}/.ryeinstall.XXXXXXXX"` +TEMP_FILE_GZ="${TEMP_FILE}.gz" + +cleanup() { + rm -f "$TEMP_FILE" + rm -f "$TEMP_FILE_GZ" +} + +trap cleanup EXIT +HTTP_CODE=$(curl -SL --progress-bar "$DOWNLOAD_URL" --output "$TEMP_FILE_GZ" --write-out "%{http_code}") +if [[ ${HTTP_CODE} -lt 200 || ${HTTP_CODE} -gt 299 ]]; then + echo "error: platform ${PLATFORM} (${ARCH}) is unsupported." + exit 1 +fi + +rm -f "$TEMP_FILE" +gunzip "$TEMP_FILE_GZ" +chmod +x "$TEMP_FILE" + +# Detect when the file cannot be executed due to NOEXEC /tmp. Taken from rustup +# https://github.com/rust-lang/rustup/blob/87fa15d13e3778733d5d66058e5de4309c27317b/rustup-init.sh#L158-L159 +if [ ! -x "$TEMP_FILE" ]; then + printf '%s\n' "Cannot execute $TEMP_FILE (likely because of mounting /tmp as noexec)." 1>&2 + printf '%s\n' "Please copy the file to a location where you can execute binaries and run it manually." 1>&2 + exit 1 +fi + +"$TEMP_FILE" self install $INSTALL_OPTION + +}; __wrap__ diff --git a/guide/basics/index.html b/guide/basics/index.html new file mode 100644 index 0000000000..920b008fdd --- /dev/null +++ b/guide/basics/index.html @@ -0,0 +1,1001 @@ + + + + + + + + + + + + + + + + + + + + + + + + Basics - Rye + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + + +
+
+
+ + + + +
+
+ + + + + + + + + + + + +

Basics

+

To use Rye you need to have a pyproject.toml based Python project. For this guide you can +create one with rye init which will create a new folder with a new project inside:

+
rye init my-project
+cd my-project
+
+

The following structure will be created:

+
.
+├── .git
+├── .gitignore
+├── .python-version
+├── README.md
+├── pyproject.toml
+└── src
+    └── my_project
+        └── __init__.py
+
+
+

Good to Know

+

The init command accepts a lot of options to customize what it generates. Run +rye init --help to see all the options available in the version you have installed.

+
+

A pyproject.toml is used to store metadata about your project as well as some Rye +configuration. Most of Rye's commands will require a pyproject.toml to work. Note +that Rye today does not support setup.py based projects. Note that when Rye initializes +a project it also writes a .python-version file. This file contains the version number +of the Python version that should be used for this project. It can be changed by +running rye pin. For instance to tell Rye to use Python 3.10:

+
$ rye pin 3.10
+
+

First Sync

+

Once that is done, you can use rye sync to get the first synchronization. After that, +Rye will have created a virtualenv in .venv and written lockfiles into requirements.lock +and requirements-dev.lock.

+
rye sync
+
+

The virtualenv that Rye manages is placed in .venv next to your pyproject.toml. +The first time you run this you will notice that Rye automatically downloaded and +installed a compatible CPython interpreter for you. If you have already another +Python installation on your system it will not be used! For more information about +this behavior read about toolchains.

+

You can activate and work with it as normal with one notable exception: the Python +installation in it does not contain pip. If you have correctly installed Rye +with the shims enabled, after the sync you can run python and you will automatically +be operating in that virtualenv, even if it's not enabled. You can validate this +by printing out sys.prefix:

+
python -c "import sys; print(sys.prefix)"
+
+

It will print out the full path to the managed virtualenv.

+

Adding Dependencies

+

Use the add command to add dependencies to your project.

+
rye add "flask>=2.0"
+
+

Note that after add you need to run sync again to actually install it. If you +want to add packages from custom indexes, you have to configure the source +first.

+

Remove a Dependency

+

Use the remove command to remove a dependency from the project again.

+
rye remove flask
+
+

Working with the Project

+

To run executables in the context of the virtualenv you can use the run command. For +instance if you want to use black you can add and run it like this:

+
rye add black
+rye sync
+rye run black
+
+

If you want to have the commands available directly you will need to activate the +virtualenv like you do normally. To activate the virtualenv, use the standard methods:

+
+
+
+
. .venv/bin/activate
+
+
+
+
.venv\Scripts\activate
+
+
+
+
+

To deactivate it again run deactivate:

+
deactivate
+
+

Inspecting the Project

+

The rye show command can print out information about the project's state. By +just running rye show you can see which Python version is used, where the +virtualenv is located and more. You can also invoke rye show --installed-deps +to get a dump of all installed dependencies.

+
rye show
+rye show --installed-deps
+
+ + + + + + +
+
+ + + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/guide/config/index.html b/guide/config/index.html new file mode 100644 index 0000000000..b2e4453ae1 --- /dev/null +++ b/guide/config/index.html @@ -0,0 +1,1027 @@ + + + + + + + + + + + + + + + + + + + + + + + + Configuration - Rye + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + + +
+
+
+ + + + +
+
+ + + + + + + + + + + + +

Configuration

+

Most of Rye's configuration is contained within the pyproject.toml file. There is however +also a bit of global configuration to influence how it works.

+

Changing Home Folder

+

By default Rye places all it's configuration in ~/.rye on Unix and %USERPROFILE%\.rye on +Windows. This behavior can be changed via the RYE_HOME environment variable. This is useful +if you do not like the default location of where Rye places it's configuration or if you need +to isolate it.

+

Home Folder Structure

+

The .rye home folder contains both user configuration as well as Rye managed state such +as installed toolchains. The following files and folders are placed within the +.rye folder. Note that not all are there always.

+

config.toml

+

This is a configuration file that influences how Rye operates. Today very little configuration +is available there. For the available config keys see Config File.

+

self

+

While Rye is written in Rust, it uses a lot of Python tools internally. These are maintained in +an internal virtualenv stored in this location.

+

py

+

In this folder Rye stores the different toolchains. Normally those are folders +containing downloaded Python distributions, but they can also be symlinks or special reference +files.

+

shims

+

This folder contains shim binaries. These binaries are for instance the python executable +which automatically proxies to the current virtualenv or globally installed tools.

+

Config File

+

The config file config.toml in the .rye folder today only is used to manage defaults. This +is a fully annotated config file:

+
[default]
+# This is the default value that is written into new pyproject.toml
+# files for the `project.requires-python` key
+requires-python = ">= 3.8"
+
+# This is the default toolchain that is used
+toolchain = "cpython@3.11.1"
+
+# This is the default build system that is used
+build-system = "hatchling"
+
+# This is the default license that is used
+license = "MIT"
+
+# This sets the default author (overrides the defaults from git).  The
+# format here is "Name <email>".
+author = "Full Name <email@address.invalid>"
+
+# The dependency operator to use by default for dependencies.  The options are
+# '>=', '~=', and '=='.  The default currently is '>='.  This affects the behavior
+# of `rye add`.
+dependency-operator = ">="
+
+[proxy]
+# the proxy to use for HTTP (overridden by the http_proxy environment variable)
+http = "http://127.0.0.1:4000"
+# the proxy to use for HTTPS (overridden by the https_proxy environment variable)
+https = "http://127.0.0.1:4000"
+
+[behavior]
+# When set to true the `managed` flag is always assumed to be true.
+force-rye-managed = false
+
+# Enables global shims when set to `true`.  This means that the installed
+# `python` shim will resolve to a Rye managed toolchain even outside of
+# virtual environments.
+global-python = false
+
+# a array of tables with optional sources.  Same format as in pyproject.toml
+[[sources]]
+name = "default"
+url = "http://pypi.org/simple/"
+
+

Manipulating Config

+
+

new in 0.9.0

+
+

The configuration can be read and modified with rye config. The +keys are in dotted notation. --get reads a key, --set, --set-int, +--set-bool, or --unset modify one.

+
rye config --set proxy.http=http://127.0.0.1:4000
+rye config --set-bool behavior.force-rye-managed=true
+rye config --get default.requires-python
+
+

Per Project Config

+

For the project specific pyproject.toml config see pyproject.toml.

+ + + + + + +
+
+ + + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/guide/deps/index.html b/guide/deps/index.html new file mode 100644 index 0000000000..5f0b8127d6 --- /dev/null +++ b/guide/deps/index.html @@ -0,0 +1,940 @@ + + + + + + + + + + + + + + + + + + + + + + + + Dependencies - Rye + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + + +
+
+
+ + + + +
+
+ + + + + + + + + + + + +

Dependencies

+

Dependencies are declared in pyproject.toml however adding them can be +simplified with the rye add command. In the most simple invocation it adds a regular +dependency, but it can be customized.

+

Adding Basic Dependency

+

To add a regular dependency just invoke rye add with the name of the Python package:

+
rye add Flask
+
+

If you also want to define a version, use a PEP 508 +requirement:

+
rye add "Flask>=2.0"
+
+

For extra/feature dependencies you can either use PEP 508 syntax or use --features:

+
rye add "Flask[dotenv]"
+rye add Flask --features=dotenv
+
+

These dependencies are stored in project.dependencies.

+
+

Note about pre-releases

+

By default add will not consider pre-releases. This means if you add a dependency +that has .dev or similar in the version number you will not find a match. To +consider them, add them with --pre:

+
rye add "Flask==2.0.0rc2" --pre
+
+
+

Development Dependencies

+

For dependencies that should only be installed during development pass --dev

+
rye add --dev black
+
+

These dependencies are stored in the non-standard +tool.rye.dev-dependencies key.

+

To run tools added this way without enabling the virtualenv use rye run:

+
rye run black
+
+

Git / Local Dependencies

+

To add a local or git dependency, you can pass additional parameters like --path +or --git:

+
rye add Flask --git=https://github.com/pallets/flask
+rye add My-Utility --path ./my-utility
+
+

Note that when adding such dependencies, it's necessary to also provide the name +of the package. Additionally for git dependencies all kinds of extra parameters +such as --tag, --rev or --branch are supported.

+

When working with local dependencies it's strongly encouraged to configure a +workspace.

+ + + + + + +
+
+ + + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/guide/faq/index.html b/guide/faq/index.html new file mode 100644 index 0000000000..0808bbc60c --- /dev/null +++ b/guide/faq/index.html @@ -0,0 +1,1009 @@ + + + + + + + + + + + + + + + + + + + + + + + + FAQ - Rye + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + + +
+
+
+ + + + +
+
+ + + + + + + + + + + + +

FAQ

+

This section should cover some commonly asked questions. If you do not find an answer +here, consider reaching out to the community.

+

Windows Developer Mode

+

Rye does not require symlinks but it works significantly better with them. On Windows +support for symlinks is restricted to privileged accounts. The reason for this is that +Symlinks were a late addition to Windows and some applications are not developed with +them in mind which can cause misbehavior or in the worst case security issues in those +applications. Symlinks support however is enabled when the "developer mode" is activated +on modern Windows versions. Here is how you can enable it:

+
    +
  1. Press Win+I to open the settings
  2. +
  3. In the settings dialog click on "Privacy & security"
  4. +
  5. In the "Security" section click on "For developers"
  6. +
  7. Enable the toggle "Developer Mode"
  8. +
  9. In the "Use developer features" dialog confirm by clicking "Yes".
  10. +
+
+What happens if I don't enable it? +

Enabling symlinks is not strictly required as Rye automatically falls back to +hardlinks and junction points. However not having symlinks enabled will ultimately +result in a worse user experience for the following reasons:

+
    +
  • Custom toolchain registration uses proxy files rather than actual symlinks which + means that the executables in the .rye\py path are non executable.
  • +
  • All shims will be installed as hardlinks. This can cause issues when upgrading + Rye while Python is in use. These hardlinks will also continue to point to older + Rye executables creating more hard drive usage.
  • +
  • Virtualenvs will be created with copies rather than symlinks.
  • +
  • Junction points are used where symlinks to directories are otherwise used. Some + tools might accidentally not detect junction points which can cause deletion of + virtualenvs to accidentally also delete or destroy the toolchain behind it.
  • +
+
+

Missing Shared Libraries on Linux

+

The Python builds that Rye uses require a Linux installation compatible to the +Linux Standard Base Core Specification (LSB). Unfortunately not all Linux +distributions are strictly adhering to that specification out of the box. In +particularly the library libcrypt.so.1 is commonly not installed on certain +Linux distributions but the _crypt standard library module depends on it. +Depending on the Linux distributions you need to run different commands to +resolve this:

+
    +
  • archlinux: pacman -S libxcrypt-compat
  • +
  • CentOS/RedHat: dnf install libxcrypt-compat
  • +
+

There have also been reports of an error being generated at installation time +despite libcrypt.so.1 being installed when a different ldd (eg: Homebrew) +shadows the system one. In that case try the installation again after giving +the default one higher priority in the `PATH:

+
export PATH="/usr/bin:$PATH"
+curl -sSf https://rye-up.com/get | bash
+
+

TKinter Support

+

TKinter uses TCL behind the scenes. Unfortunately this also means that some runtime +support is required. This runtime support is provided by the portable Python builds, +however the way TCL is initialized on macOS and Linux won't find these files in +virtualenvs. Newer versions of Rye will automatically export the TCL_LIBRARY +and TK_LIBRARY environment variables for you in a manner very similar to this:

+
import os
+import sys
+os.environ["TCL_LIBRARY"] = sys.base_prefix + "/lib/tcl8.6"
+os.environ["TK_LIBRARY"] = sys.base_prefix + "/lib/tk8.6"
+
+

Python Interactive Prompt Input Messed Up

+

The Python builds that Rye uses are compiled against libedit rather than readline +for licensing reasons. You might run into unicode issues on input as a result of this +due to limitations in libedit. In some cases though you might also discover that +the backspace key does not work or arrow keys don't work as expected. This can be +because the terminfo database cannot be found.

+

For solutions to this issue, read the behavior quirks guide in the +Standalone Python Builds documentation for solutions.

+

Can I use Rye Alongside Other Python Installations?

+

Rye given it's experimental nature does not want to disrupt already existing Python +workflows. As such using it alongside other Python installations is intentionally +supported. Even if the Rye shims come first on the PATH, Rye will automatically +resolve to a different Python installation on the search path when invoked in a +folder that contains a non Rye managed project.

+

As such the answer is a clear yes!

+

Wheels Appear to be Missing Files

+

You might be encountering missing files in wheels when running rye build and you +are using hatchling. The reason for this is that rye build uses +"build" behind the scenes to build wheels. There +are two build modes and in some cases the wheel is first built from an sdist. So +if your sdists does not include the necessary data files, the resulting wheel will +also be incorrect.

+

This can be corrected by adding the files to the include in the hatch config +for sdists. For instance the following lines added to pyproject.toml will add +the data files in my_package and all the tests to the sdist from which the +wheel is built:

+
[tool.hatch.build.targets.sdist]
+include = ["src/my_package", "tests"]
+
+ + + + + + +
+
+ + + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/guide/index.html b/guide/index.html new file mode 100644 index 0000000000..a21d465834 --- /dev/null +++ b/guide/index.html @@ -0,0 +1,869 @@ + + + + + + + + + + + + + + + + + + + + + + + + Introduction - Rye + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + + +
+
+
+ + + + +
+
+ + + + + + + + + + + + +

Introduction

+

Rye is still a very experimental tool, but this guide is here to help you get +started. Before we dive into the installation and basic usage guide it's +important for you to understand what Rye actually is.

+

Rye is a one-stop-shop tool. The idea is that as a Python developer all you +need to know is Rye, because Rye is your start into the experience. As a Rye +user you do not even need to install Python yourself as Rye does this for you. +This means to use Rye, you just need to install Rye, the rest is done by Rye +itself.

+

Once Rye is on your system, it can automatically install Python interpreters +for you, install packages from package indexes, manage virtualenvs behind +the scenes and more.

+
+ +
+ +

Interested? Then head over to Installation to learn about +how to get Rye onto your system. Once that is done, read the Basics +to learn about how Rye can be used.

+ + + + + + +
+
+ + + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/guide/installation/index.html b/guide/installation/index.html new file mode 100644 index 0000000000..362e9d8290 --- /dev/null +++ b/guide/installation/index.html @@ -0,0 +1,1200 @@ + + + + + + + + + + + + + + + + + + + + + + + + Installation - Rye + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + + +
+
+
+ + + + +
+
+ + + + + + + + + + + + +

Installation

+

Rye is built in Rust. It can either be manually compiled and installed or it can +be installed from a binary distribution. It has support for Linux, macOS and +Windows.

+

Installing Rye

+

Rye is installed per-user and self manages itself. It will install itself into +a folder in your home directory and mange itself there.

+ +
+
+
+

To install run you can curl a command which will install the right binary for your +operating system and CPU architecture and install it:

+
curl -sSf https://rye-up.com/get | bash
+
+

Alternatively if you don't trust this approach, you can download the latest release +binary. On first run it will install itself.

+ +
gunzip rye-x86_64-linux.gz
+chmod +x ./rye-x86_64-linux
+./rye-x86_64-linux
+
+
+
+

To install run you can curl a command which will install the right binary for your +operating system and CPU architecture and install it:

+
curl -sSf https://rye-up.com/get | bash
+
+

Alternatively if you don't trust this approach, you can download the latest release +binary. On first run it will install itself.

+ +
gunzip rye-aarch64-macos.gz
+chmod +x ./rye-aarch64-macos
+./rye-aarch64-macos
+
+
+
+

To install Rye on windows download the latest release and run the binary. Upon +first run it will install itself. Please note that it's strongly recommended +to have "Developer Mode" activated when using Rye and before starting the +installation. Learn more.

+ +
+

Note

+

Rye does not yet use signed binaries which means that you will need to allow +the execution of the downloaded executable. If there is no obvious way to do so, click +on "More info" on the error message that shows up and then on "Run anyway".

+
+
+
+

You need to have Rust and Cargo installed. If you don't have, you can use +rustup to get them onto your machine.

+

Afterwards you can install Rye via cargo:

+
cargo install --git https://github.com/mitsuhiko/rye rye
+
+
+
+
+ + +

Rye will automatically download suitable Python toolchains as needed. For more +information about this read about toolchains. To install +a specific version download a binary directly +from GitHub.

+

Customized Installation

+

On some platforms there is some limited support for customizing the installation +experience.

+
+
+
+

+The install script that is piped to bash can be customized with some environment +variables:

+
+
RYE_VERSION
+
+

Defaults to latest. Can be set to an explicit version to install a specific one.

+
+
RYE_INSTALL_OPTION
+
+

Can optionally be set to "--yes" to skip all prompts.

+
+
+
RYE_TOOLCHAIN
+
+

Optionally this environment variable can be set to point to a Python +interpreter that should be used as the internal interpreter. If not +provided a suitable interpreter is automatically downloaded.

+

At present only CPython 3.9 to 3.11 are supported.

+
+
+ +

This for instance installs a specific version of Rye without asking questions:

+

curl -sSf https://rye-up.com/get | RYE_VERSION="0.4.0" RYE_INSTALL_OPTION="--yes" bash
+
+

+
+
+

+The install script that is piped to bash can be customized with some environment +variables:

+
+
RYE_VERSION
+
+

Defaults to latest. Can be set to an explicit version to install a specific one.

+
+
RYE_INSTALL_OPTION
+
+

Can optionally be set to "--yes" to skip all prompts.

+
+
+
RYE_TOOLCHAIN
+
+

Optionally this environment variable can be set to point to a Python +interpreter that should be used as the internal interpreter. If not +provided a suitable interpreter is automatically downloaded.

+

At present only CPython 3.9 to 3.11 are supported.

+
+
+ +

This for instance installs a specific version of Rye without asking questions:

+

curl -sSf https://rye-up.com/get | RYE_VERSION="0.4.0" RYE_INSTALL_OPTION="--yes" bash
+
+

+
+
+

The Windows installer has limited support for customizations via environment +variables. To set these you need to run the installer from cmd.exe.

+
+
+
RYE_TOOLCHAIN
+
+

Optionally this environment variable can be set to point to a Python +interpreter that should be used as the internal interpreter. If not +provided a suitable interpreter is automatically downloaded.

+

At present only CPython 3.9 to 3.11 are supported.

+
+
+ +

This for instance installs Rye with a specific toolchain:

+
set RYE_TOOLCHAIN=%USERPROFILE%\AppData\Local\Programs\Python\Python310\python.exe
+rye-x86_64-windows.exe
+
+
+
+
+

Add Shims to Path

+

Once rye is installed you need to add the shims folder into your PATH. +This folder is a folder that contains "shims" which are executables that +Rye manages for you as well as the rye executable itself. For instance any +Python installation managed by Rye will be available via a shim placed there.

+

On macOS or Linux you can accomplish this by adding it to your .bashrc, .zshrc +or similar. This step is technically optional but required if you want to be able to +just type python or rye into the shell to pick up the current virtualenv's Python +interpreter.

+
+
+
+

Rye ships an env file which should be sourced to update PATH automatically.

+
echo 'source "$HOME/.rye/env"' >> ~/.bashrc
+
+
+
+

Rye ships an env file which should be sourced to update PATH automatically.

+
echo 'source "$HOME/.rye/env"' >> ~/.zshrc
+
+
+
+

Since fish does not support env files, you instead need to add +the shims directly. This can be accomplished by running this +command once:

+
set -Ua fish_user_paths "$HOME/.rye/shims"
+
+
+
+

Rye ships an env file which should be sourced to update PATH automatically.

+
echo '. "$HOME/.rye/env"' >> ~/.profile
+
+
+
+

To modify the Windows PATH environment variable

+
    +
  1. Press Win+R, enter sysdm.cpl and hit Enter.
  2. +
  3. In the "System Properties" dialog, click the "Advanced" tab.
  4. +
  5. Click on "Environment Variables".
  6. +
  7. In the top list, double click on the Path variable.
  8. +
  9. In the "Edit environment variable" dialog click on "New".
  10. +
  11. Enter %USERPROFILE%\.rye\shims and hit Enter.
  12. +
  13. Click repeatedly on "Move Up" until the newly added item is at the top.
  14. +
  15. Click on "OK" and close the dialog.
  16. +
+

Note that you might need to restart your login session for this to take effect.

+
+
+
+

There is a quite a bit to shims and their behavior. Make sure to read up on shims +to learn more.

+

Shell Completion

+

Rye supports generating completion scripts for Bash, Zsh, Fish or Powershell. Here are some common locations for each shell:

+
+
+
+
mkdir -p ~/.local/share/bash-completion/completions
+rye self completion > ~/.local/share/bash-completion/completions/rye.bash
+
+
+
+
# Make sure ~/.zfunc is added to fpath, before compinit.
+rye self completion -s zsh > ~/.zfunc/_rye
+
+

Oh-My-Zsh:

+
mkdir $ZSH_CUSTOM/plugins/rye
+rye self completion -s zsh > $ZSH_CUSTOM/plugins/rye/_rye
+
+

Then make sure rye plugin is enabled in ~/.zshrc

+
+
+
rye self completion -s fish > ~/.config/fish/completions/rye.fish
+
+
+
+
# Create a directory to store completion scripts
+mkdir $PROFILE\..\Completions
+echo @'
+Get-ChildItem "$PROFILE\..\Completions\" | ForEach-Object {
+    . $_.FullName
+}
+'@ | Out-File -Append -Encoding utf8 $PROFILE
+# Generate script
+Set-ExecutionPolicy Unrestricted -Scope CurrentUser
+rye self completion -s powershell | Out-File -Encoding utf8 $PROFILE\..\Completions\rye_completion.ps1
+
+
+
+
+

Updating Rye

+

To update rye to the latest version you can use rye itself:

+
rye self update
+
+

Uninstalling

+

If you don't want to use Rye any more, you can ask it to uninstall it again:

+
rye self uninstall
+
+

Additionally you should delete the remaining .rye folder from your home directory and +remove .rye/shims from the PATH again. Rye itself does not place any data +in other locations. Note though that virtual environments created by rye will +no longer function after Rye was uninstalled.

+

Preventing Auto Installation

+

Rye when launched will normally perform an auto installation. This can be annoying +in certain development situations. This can be prevented by exporting the +RYE_NO_AUTO_INSTALL environment variable. It needs to be set to 1 to disable +the feature.

+
+
+
+
export RYE_NO_AUTO_INSTALL=1
+
+
+
+
export RYE_NO_AUTO_INSTALL=1
+
+
+
+
set RYE_NO_AUTO_INSTALL=1
+
+
+
+
+ + + + + + +
+
+ + + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/guide/publish/index.html b/guide/publish/index.html new file mode 100644 index 0000000000..501e4abec1 --- /dev/null +++ b/guide/publish/index.html @@ -0,0 +1,940 @@ + + + + + + + + + + + + + + + + + + + + + + + + Building and Publishing - Rye + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + + +
+
+
+ + + + +
+
+ + + + + + + + + + + + +

Building and Publishing

+

Rye currently uses build to build the package and uses twine to publish it.

+

Build

+

By default, rye will build the both sdist and wheel target in the dist directory.

+
rye build
+
+

You can use the --sdist or --wheel flag to build the specific target, or specify the output directory with --out.

+
rye build --wheel --out target
+
+

If you want to clean the build directory before building, run:

+
rye build --clean
+
+

Publish

+

Rye will publish the distribution files under the dist directory to PyPI by default.

+
rye publish
+
+

You might be asked to input your access token and some other info if needed.

+
No access token found, generate one at: https://pypi.org/manage/account/token/
+Access token:
+
+

You can also specify the distribution files to be published:

+
rye publish dist/example-0.1.0.tar.gz
+
+

--repository

+

Rye supports publishing the package to a different repository by using the --repository and --repository-url flags. For example, to publish to the test PyPI repository:

+
rye publish --repository testpypi --repository-url https://test.pypi.org/legacy/
+
+

--yes

+

You can optionally set the --yes flag to skip the confirmation prompt. This can be useful for CI/CD pipelines.

+
rye publish --token <your_token> --yes
+
+

Rye will store your repository info in $HOME/.rye/credentials for future use.

+ + + + + + +
+
+ + + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/guide/pyproject/index.html b/guide/pyproject/index.html new file mode 100644 index 0000000000..cc322c8580 --- /dev/null +++ b/guide/pyproject/index.html @@ -0,0 +1,1099 @@ + + + + + + + + + + + + + + + + + + + + + + + + Python Project - Rye + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + + +
+
+
+ + + + +
+
+ + + + + + + + + + + + +

Python Project (pyproject.toml)

+

Rye tries to avoid a lot of proprietary configuration in the pyproject.toml file but a bit +is necessary. Here are the most important keys that Rye expects:

+

project.dependencies

+

This key is used to manage dependencies. They work exactly like you expect from a regular +pyproject.toml file and in fact Rye changes nothing about this. However Rye is capable +of modifying these entries with the rye add and rye remove commands.

+
[project]
+dependencies = [
+    "mkdocs~=1.4.3",
+    "mkdocs-material~=9.1.12",
+    "pymdown-extensions~=9.11",
+]
+
+

project.scripts

+

This key specifies the scripts that are to be generated and installed into the virtual environment during sync. +These scripts will invoke the configured entry point.

+

[project.scripts]
+my-hello-script = 'hello:main'
+
+This configuration will generate a script my-hello-script that will call the main function of the +hello module.

+

Scripts can be installed using rye sync and run using rye run:

+
$ rye sync
+$ rye run my-hello-script
+Hello from hello!
+
+

tool.rye.dev-dependencies

+

This works similar to project.dependencies but holds development only dependencies. These +can be added here automatically via rye add --dev.

+
[tool.rye]
+dev-dependencies = ["black~=23.3.0"]
+
+

Dev dependencies are installed automatically unless --no-dev is passed to sync.

+

tool.rye.excluded-dependencies

+

This is a special key that contains dependencies which are never installed, even if they are +pulled in as indirect dependencies. These are added here automatically with rye add --excluded.

+
[tool.rye]
+excluded-dependencies = ["cffi"]
+
+

tool.rye.lock-with-sources

+
+

new in 0.18.0

+
+

When this flag is enabled all lock and sync operations in the project or workspace +operate as if --with-sources is passed. This means that all lock files contain the +full source references. Note that this can create lock files that contain credentials +if the sources have credentials included in the URL.

+
[tool.rye]
+lock-with-sources = true
+
+

tool.rye.managed

+
+

new in 0.3.0

+
+

This key tells rye that this project is supposed to be managed by Rye. This key +primarily affects some automatic creation of virtualenvs. For instance Rye +will not try to initialize a virtualenv when using shims without this flag. It +can be forced enabled in the global config.

+
[tool.rye]
+managed = true
+
+

tool.rye.sources

+

This is an array of tables with sources that should be used for locating dependencies. +This lets you use indexes other than PyPI. These sources can also be configured in the +main config.toml config file with the same syntax.

+
[[tool.rye.sources]]
+name = "default"
+url = "http://pypi.org/simple/"
+
+

For more information about configuring sources see Dependency Sources.

+

tool.rye.scripts

+

This key can be used to register custom scripts that are exposed via rye run. Each key is +a script, and each value is the configuration for that script. Normally the value is an object +with different keys with the most important key being cmd which holds the command to execute. +However if only cmd is set, then the object is optional. cmd itself can either be set to a +string or an array of arguments.

+
[tool.rye.scripts]
+# These three options are equivalent:
+devserver = "flask run --app ./hello.py --debug"
+devserver-alt = ["flask", "run", "--app", "./hello.py", "--debug"]
+devserver-explicit = { cmd = "flask run --app ./hello.py --debug" }
+
+

The following keys are possible for a script:

+

cmd

+

The command to execute. This is either a string or an array of arguments. In either case +shell specific interpolation is unavailable. The command will invoke one of the tools in the +virtualenv if it's available there.

+
[tool.rye.scripts]
+devserver = { cmd = "flask run --app ./hello.py --debug" }
+http = { cmd = ["python", "-mhttp.server", "8000"] }
+
+

env

+

This key can be used to provide environment variables with a script:

+
[tool.rye.scripts]
+devserver = { cmd = "flask run --debug", env = { FLASK_APP = "./hello.py" } }
+
+

chain

+

This is a special key that can be set instead of cmd to make a command invoke multiple +other commands. Each command will be executed one after another. If any of the commands +fails the rest of the commands won't be executed and instead the chain fails.

+
[tool.rye.scripts]
+lint = { chain = ["lint:black", "lint:flake8" ] }
+"lint:black" = "black --check src"
+"lint:flake8" = "flake8 src"
+
+

call

+

This is a special key that can be set instead of cmd to make a command invoke python +functions or modules. The format is one of the three following formats:

+
    +
  • <module_name>: equivalent to python -m <module_name>
  • +
  • <module_name>:<function_name>: runs <function_name> from <module_name> and exits with the return value
  • +
  • <module_name>:<function_name>(<args>): passes specific arguments to the function
  • +
+

Extra arguments provided on the command line are passed in sys.argv.

+
[tool.rye.scripts]
+serve = { call = "http.server" }
+help = { call = "builtins:help" }
+hello-world = { call = "builtins:print('Hello World!')" }
+
+

tool.rye.workspace

+

When a table with that key is stored, then a project is declared to be a workspace root. By +default all Python projects discovered in sub folders will then become members of this workspace +and share a virtualenv. Optionally the members key (an array) can be used to restrict these +members. In that list globs can be used. The root project itself is always a member.

+
[tool.rye.workspace]
+members = ["mylib-*"]
+
+ + + + + + +
+
+ + + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/guide/rust/index.html b/guide/rust/index.html new file mode 100644 index 0000000000..aaa218d1d4 --- /dev/null +++ b/guide/rust/index.html @@ -0,0 +1,927 @@ + + + + + + + + + + + + + + + + + + + + + + + + Rust Modules - Rye + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + + +
+
+
+ + + + +
+
+ + + + + + + + + + + + +

Rust Modules

+

Rye recommends using maturin to develop Rust Python +extension modules. This process is largely automated and new projects can be created +with rye init.

+

New Project

+
rye init my-project --build-system maturin
+cd my-project
+
+

The following structure will be created:

+
.
+├── .git
+├── .gitignore
+├── .python-version
+├── README.md
+├── pyproject.toml
+├── Cargo.toml
+├── python
+    └── my_project
+        └── __init__.py
+└── src
+    └── lib.rs
+
+

Iterating

+

When you use maturin as a build system then rye sync will automatically build the rust +extension module into your venv. Likewise rye build will use maturin to trigger a +wheel build. For faster iteration it's recommended to use maturin directly.

+

If you want to use other maturin commands such as maturin develop you can install +it as a global tool:

+
rye install maturin
+
+

Note that maturin develop requires pip to be installed into the virtualenv. Before +you can use it you need to add it:

+
rye add --dev pip
+rye sync
+
+

Rye recommends mixed python/rust modules. In that case you can save some valuable +iteration time by running maturin develop --skip-install:

+
maturin develop --skip-install
+
+ + + + + + +
+
+ + + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/guide/shims/index.html b/guide/shims/index.html new file mode 100644 index 0000000000..c1765750c7 --- /dev/null +++ b/guide/shims/index.html @@ -0,0 +1,914 @@ + + + + + + + + + + + + + + + + + + + + + + + + Shims - Rye + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + + +
+
+
+ + + + +
+
+ + + + + + + + + + + + +

Shims

+

After installation Rye places two shims on your PATH: python and python3. These +shims have specific behavior that changes depending on if they are used within a Rye +managed project or outside.

+

Inside a Rye managed project they resolve to the Python interpreter of the virtualenv. +This means that even if you do not enable the virtualenv, you can just run python +in a shell, and it will automatically operate in the right environment.

+

Outside a Rye managed project it typically resolves to your system Python, though you +can also opt to have it resolve to a Rye managed Python installation for you. This is +done so that it's not disruptive to your existing workflows which might depend on the +System python installation.

+

Global Shims

+
+

new in 0.9.0

+
+

To enable global shims, you need to enable the global-python flag in +the config.toml file:

+
rye config --set-bool behavior.global-python=true
+
+

Afterwards if you run python outside of a Rye managed project it will +spawn a Python interpreter that is shipped with Rye. It will honor the +closest .python-version file for you. Additionally you can also +explicitly request a specific Python version by adding +VERSION after +the python command. For instance this runs a script with Python 3.8:

+
python +3.8 my-script.py
+
+
+

Note

+

Selecting a specific Python version this way only works outside of +Rye managed projects. Within Rye managed projects, the version needs +to be explicitly selected via .python-version or with the +requires-python key in pyproject.toml.

+
+ + + + + + +
+
+ + + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/guide/sources/index.html b/guide/sources/index.html new file mode 100644 index 0000000000..52170ada5c --- /dev/null +++ b/guide/sources/index.html @@ -0,0 +1,1028 @@ + + + + + + + + + + + + + + + + + + + + + + + + Dependency Sources - Rye + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + + +
+
+
+ + + + +
+
+ + + + + + + + + + + + +

Dependency Sources

+
+

new in 0.2.0

+
+

Normally Rye loads packages from PyPI only. However it is possible to instruct it to +load packages from other indexes as well.

+

Adding a Source

+

An index can be added to a project or workspace (via pyproject.toml) or into the +global config. Rye will always consult both files where the +pyproject.toml file wins over the global config.

+

Each source needs to have a unique name. The default source is always called default +and out of the box points to PyPI.

+
+
+
+

Add this to ~/.rye/config.toml:

+
[[sources]]
+name = "company-internal"
+url = "https://company.internal/simple/"
+
+
+
+

Add this to pyproject.toml:

+
[[tool.rye.sources]]
+name = "company-internal"
+url = "https://company.internal/simple/"
+
+
+
+
+
+

changed in 0.4.0

+

Sources in the global config are also considered for tool installations.

+
+

Index Types

+

Rye supports different types of sources and also allows overriding the default +PyPI index. If you give another source the name default, PyPI will no longer be +used for resolution.

+
+
+
+
[[sources]]
+name = "company-internal"
+url = "https://company.internal/simple/"
+type = "index"  # this is implied
+
+
+
+
[[sources]]
+name = "company-internal"
+url = "https://company.internal/"
+type = "find-links"
+
+
+
+
[[sources]]
+name = "default"
+url = "https://company.internal/simple/"
+
+
+

Warning

+

Please take note that the default index cannot be of type find-links.

+
+
+
+
+

Source Types

+

The two sources types (index vs find-links) are determined by the underlying pip +infrastructure:

+

index

+

This is a PEP 503 type index as provided +by tools such as PyPI or devpi. It corresponds to +the arguments --index-url or --extra-index-url in pip.

+ +

This is a source that can be of a variety of types and has to point to a file path +or hosted HTML page linking to packages. It corresponds to the --find-links +argument. The format of the HTML page is somewhat underspecified but generally +all HTML links pointing to .tar.gz or .whl files are considered.

+

Index Authentication

+

HTTP basic auth is supported for index authentication. It can be supplied in two +ways. username and password can be directly embedded in the config, or they +can be supplied with environment variables.

+
+
+
+
[[sources]]
+name = "company-internal"
+url = "https://company.internal/simple/"
+username = "username"
+password = "super secret"
+
+
+
+
[[sources]]
+name = "company-internal"
+url = "https://${INDEX_USERNAME}:${INDEX_PASSWORD}@company.internal/simple/"
+
+
+
+
+ + + + + + +
+
+ + + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/guide/sync/index.html b/guide/sync/index.html new file mode 100644 index 0000000000..4f2165e87e --- /dev/null +++ b/guide/sync/index.html @@ -0,0 +1,1001 @@ + + + + + + + + + + + + + + + + + + + + + + + + Syncing and Locking - Rye + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + + +
+
+
+ + + + +
+
+ + + + + + + + + + + + +

Syncing and Locking

+

Rye currently uses pip-tools to download and install +dependencies. For this purpose it creates two "lockfiles" (called requirements.lock and +requirements-dev.lock). These are not real lockfiles but they fulfill a similar purpose +until a better solution has been implemented.

+

Whenever rye sync is called, it will update lockfiles as well as the virtualenv. If you only +want to update the lockfiles, then rye lock can be used.

+

Lock

+

When locking, some options can be provided to change the locking behavior. These flags are +also all available on rye sync.

+

--update / --update-all

+

Updates a specific or all requirements to the latest and greatest version. Without this flag +a dependency will only be updated if necessary.

+
rye lock --update-all
+
+

--features / --all-features

+

Python packages can have extra dependencies. By default the local package that is installed +will only be installed with the default features. If for instance you have an extra dependency +this will only be installed if the feature is enabled.

+
rye add --optional=web flask
+rye lock --features=web
+
+

When working with workspaces, the package name needs to be prefixed with a slash:

+
rye lock --features=package-name/feature-name
+
+

The --features parameter can be passed multiple times and features can also be comma +separated. To turn on all features, the --all-features parameter can be used.

+
rye lock --all-features
+
+

--pre

+

By default updates and version resolution will not consider pre-releases of packages. If you +do want to include those, pass --pre

+
rye lock Flask --pre
+
+

--with-sources

+
+

new in 0.18.0

+
+

By default (unless the tool.rye.lock-with-sources config key is set to true in the +pyproject.toml) lock files are not generated with source references. This means that +if custom sources are used the lock file cannot be installed via pip unless also +--find-links and other parameters are manually passed. This can be particularly useful +when the lock file is used for docker image builds.

+

When this flag is passed then the lock file is generated with references to --index-url, +--extra-index-url or --find-links.

+
rye lock --with-sources
+
+

Sync

+

Syncing takes the same parameters as lock and then some. Sync will usually first do what +lock does and then use the lockfiles to update the virtualenv.

+

--no-lock

+

To prevent the lock step from automatically running, pass --no-lock.

+
rye sync --no-lock
+
+

--no-dev

+

Only sync based on the production lockfile (requirements.lock) instead of the development +lockfile (requirements-dev.lock).

+
rye sync --no-dev
+
+ + + + + + +
+
+ + + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/guide/toolchains/cpython/index.html b/guide/toolchains/cpython/index.html new file mode 100644 index 0000000000..dc465a5c57 --- /dev/null +++ b/guide/toolchains/cpython/index.html @@ -0,0 +1,945 @@ + + + + + + + + + + + + + + + + + + + + + + + + Portable CPython - Rye + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + + +
+
+
+ + + + +
+
+ + + + + + + + + + + + +

Portable CPython

+

Rye is capable (and prefers) to download its own Python distribution over what +you might already have on your computer. For CPython, the +indygreg/python-build-standalone +builds from the PyOxidizer project are used.

+

The motivation for this is that it makes it easy to switch between Python +versions, to have a common experience across different Rye users and to +avoid odd bugs caused by changes in behavior.

+

Unfortunately Python itself does not release binaries (or the right types of +binaries) for all operating systems which is why Rye leverages the portable +Python builds from PyOxidizer.

+

Unlike many other Python versions you can install on your computer are +non-portable which means that if you move them to a new location on your +machine, or you copy it onto another computer (even with the same operating +system) they will no longer run. This is undesirable for what Rye wants to do. +For one we want the same experience for any of the Python developers, no matter +which operating system they used. Secondly we want to enable self-contained +Python builds later, which requires that the Python installation is portable.

+

To achieve this, the Python builds we use come with some changes that are +different from a regular Python build.

+

Limitations

+

The following changes to a regular Python versions you should be aware of:

+
    +
  • +

    libedit instead of readline: unfortunately readline is GPL2 licensed + and this is a hazard for redistributions. As such, the portable Python + builds link against the more freely licensed libedit instead.

    +
  • +
  • +

    dbm.gnu is unavailable. This is a rather uncommonly used module and the + standard library provides alternatives.

    +
  • +
+

Additionally due to how these builds are created, there are some other quirks +you might run into related to terminal support or TKinter. Some of these +issues are collected in the FAQ. Additionally the Python +Standalone Builds have a Behavior Quirks +page.

+

Sources

+

Portable CPython builds are downloaded from GitHub +(indygreg/python-build-standalone/releases) +and SHA256 hashes are generally validated. Some older versions might not +have hashes available in which case the validation is skipped.

+

Usage

+

When you pin a Python version to cpython@major.minor.patch (or just +major.minor.patch) then Rye will automatically download the right version +for you whenever it is needed. If a custom toolchain has already been registered with that name and +version, that this is used instead.

+ + + + + + +
+
+ + + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/guide/toolchains/index.html b/guide/toolchains/index.html new file mode 100644 index 0000000000..22943d5d3d --- /dev/null +++ b/guide/toolchains/index.html @@ -0,0 +1,1002 @@ + + + + + + + + + + + + + + + + + + + + + + + + Toolchain Management - Rye + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + + +
+
+
+ + + + +
+
+ + + + + + + + + + + + +

Toolchain Management

+

Rye is unique in that it does not use system Python installations. Instead it downloads +and manages Python installations itself (called toolchains). Today there are +three types of toolchains supported by Rye and they require some understanding:

+ +

Pinning Toolchains

+

To make a project use a specific toolchain write the name of the toolchain into the +.python-version file or use the pin command. For pinning cpython the cpython@ +prefix can be omitted.

+
rye pin cpython@3.11.4
+
+

Pinning a downloadable version means that Rye will automatically fetch it when necessary. +By default, toolchains are pinned to a precise version. This means that even if you +write rye pin cpython@3.11, a very specific version of cpython is written into the +.python-version file. With Rye 0.5.0 onwards it's possible to perform "relaxed" pins:

+
rye pin --relaxed cpython@3.11
+
+

This will then persist 3.11 in the .python-version file and Rye will use the latest +available compatible version for the virtual environment.

+
+

changed in 0.5.0

+

Relaxed pinning with rye pin --relaxed was added.

+
+

Non Native Architectures

+
+

new in 0.14.0

+

Support for fetching and pinning of non-native architectures was added.

+
+

By default, the pin is for the architecture of the running machine. This means that +if you pin cpython@3.11 on a mac with aarch64 architecture, you will use a cpython +interpreter of that CPU architecture. A different architecture can be selected by +adding -{arch} to the python family name. So for instance to force a x86_64 version +you need to pin like this:

+
rye pin cpython-x86_64@3.11
+
+

Note that such custom pins are not reflected in pyproject.toml but only .python-version.

+

Listing Toolchains

+

To see which toolchains are installed, rye toolchain list prints a list:

+

rye toolchain list
+
+
cpython@3.11.1 (C:\Users\armin\.rye\py\cpython@3.11.1\install\python.exe)
+pypy@3.9.16 (C:\Users\armin\.rye\py\pypy@3.9.16\python.exe)
+

+

To see which toolchains can be installed, additionally pass the --include-downloadable:

+
rye toolchain list --include-downloadable
+
+

Fetching Toolchains

+

Generally Rye automatically downloads toolchains, but they can be explicitly fetched +with rye toolchain fetch (also aliased to rye fetch):

+
rye toolchain fetch cpython@3.8.5
+
+

Toolchains are fetched from two sources:

+ +

Registering Toolchains

+

Additionally, it's possible to register an external toolchain with the rye toolchain register +command.

+
rye toolchain register /path/to/python
+
+

The name of the toolchain is picked based on the interpreter. For instance +linking a regular cpython installation will be called cpython@version, whereas +linking pypy would show up as pypy@version. From Rye 0.5.0 onwards -dbg is +appended to the name of the toolchain if it's a debug build. To override the +name you can pass --name:

+
rye toolchain register --name=custom /path/to/python
+
+

Removing Toolchains

+

To remove an already fetched toolchain run rye toolchain remove. Note that this +also works for linked toolchains:

+
rye toolchain remove cpython@3.8.5
+
+
+

Warning

+

Removing an actively used toolchain will render the virtualenvs that refer to use broken.

+
+ + + + + + +
+
+ + + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/guide/toolchains/pypy/index.html b/guide/toolchains/pypy/index.html new file mode 100644 index 0000000000..1a69b49747 --- /dev/null +++ b/guide/toolchains/pypy/index.html @@ -0,0 +1,920 @@ + + + + + + + + + + + + + + + + + + + + + + + + PyPy - Rye + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + + +
+
+
+ + + + +
+
+ + + + + + + + + + + + +

PyPy

+

PyPy is supported as alternative Python distribution. +Like the portable CPython builds it's downloaded automatically. The name for +PyPy distributions is pypy.

+

Limitations

+

PyPy has some limitations compared to regular Python builds when it comes to +working with Rye. Most specifically PyPy uses some internal pypi dependencies +and you might notice warnings show up when syching. PyPy also lags behind +regular Python installations quite a bit these days so you likely need to +target older Python packages.

+

Sources

+

PyPy builds are downloaded from +downloads.python.org. These downloads +are not verified today.

+

Usage

+

When you pin a Python version to pypy@major.minor.patch then Rye will +automatically download the right version for you whenever it is needed. If a +custom toolchain has already been registered +with that name and version, that this is used instead. Note that the version +refers to the PyPy CPython version.

+

That means for instance that PyPy 7.3.11 is identified as pypy@3.9.16 as this +is the Python version it provides. As PyPy also lacks builds for some CPU +architectures, not all platforms might provide the right PyPy versions.

+ + + + + + +
+
+ + + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/guide/tools/index.html b/guide/tools/index.html new file mode 100644 index 0000000000..21ebef08d4 --- /dev/null +++ b/guide/tools/index.html @@ -0,0 +1,944 @@ + + + + + + + + + + + + + + + + + + + + + + + + Tools - Rye + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + + +
+
+
+ + + + +
+
+ + + + + + + + + + + + +

Tools

+

Rye supports global tool installations. This for instance allows you to install +tools like black or ruff globally.

+

Installing Tools

+

Use the rye tools install (aliased to rye install) command to install a tool +globally with a shim:

+
rye install ruff
+
+

Afterwards the tool is installed into ~/.rye/tools/ruff and the necessary shims +are placed in ~/.rye/shims.

+
+

changed in 0.4.0

+

The install command now considers custom sources configured +in the config.toml file. For more information see Dependency Sources.

+
+

Extra Requirements

+

Some tools do not declare all of their dependencies since they might be optional. +In some cases these can be declared by passing extra features to the installer:

+
rye install black --features colorama
+
+

If dependencies are not at all specified, then they can be provided with --extra-requirement. +This is particularly sometimes necessary if the tool uses pkg_resources (part of +setuptools) but forgets to declare that dependency:

+
rye install gradio --extra-requirement setuptools
+
+

Listing Tools

+

If you want to see which tools are installed, you can use rye tools list:

+
rye tools list
+
+
black
+  black
+  blackd
+ruff
+  ruff
+
+

To also see which scripts those tools provide, also pass --include-scripts

+
rye tools list --include-scripts
+
+

Uninstalling Tools

+

To uninstall a tool again, use rye tools uninstall (aliased to rye uninstall):

+
rye uninstall black
+
+ + + + + + +
+
+ + + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/hooks.py b/hooks.py new file mode 100644 index 0000000000..b8c6529d1f --- /dev/null +++ b/hooks.py @@ -0,0 +1,6 @@ +import os +import shutil + +def copy_get(config, **kwargs): + site_dir = config['site_dir'] + shutil.copy('scripts/install.sh', os.path.join(site_dir, 'get')) \ No newline at end of file diff --git a/index.html b/index.html new file mode 100644 index 0000000000..5ff774f304 --- /dev/null +++ b/index.html @@ -0,0 +1,918 @@ + + + + + + + + + + + + + + + + + + + + + + Rye + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + + + +
+
+ + + + + + + + + + +
+
+ + + + + + + + + + + + +

Rye: An Experimental Package Management Solution for Python

+

Rye is Armin's personal one-stop-shop for all +his Python needs. It installs and manages Python installations, helps working with +pyproject.toml files, installs and uninstalls dependencies, creates and updates +virtualenvs behind the scenes. It supports monorepos and global tool installations.

+

Rye is an experimental endeavour to build a new type of packaging experience to +Python inspired by rustup and cargo from Rust. It's not yet production ready +but feedback and suggestions are greatly appreciated.

+ +

+ Star +Discuss + Sponsor +

+ +
+

Installation Instructions

+ +
+
+
+

To install run you can curl a command which will install the right binary for your +operating system and CPU architecture and install it:

+
curl -sSf https://rye-up.com/get | bash
+
+

Alternatively if you don't trust this approach, you can download the latest release +binary. On first run it will install itself.

+ +
gunzip rye-x86_64-linux.gz
+chmod +x ./rye-x86_64-linux
+./rye-x86_64-linux
+
+
+
+

To install run you can curl a command which will install the right binary for your +operating system and CPU architecture and install it:

+
curl -sSf https://rye-up.com/get | bash
+
+

Alternatively if you don't trust this approach, you can download the latest release +binary. On first run it will install itself.

+ +
gunzip rye-aarch64-macos.gz
+chmod +x ./rye-aarch64-macos
+./rye-aarch64-macos
+
+
+
+

To install Rye on windows download the latest release and run the binary. Upon +first run it will install itself. Please note that it's strongly recommended +to have "Developer Mode" activated when using Rye and before starting the +installation. Learn more.

+ +
+

Note

+

Rye does not yet use signed binaries which means that you will need to allow +the execution of the downloaded executable. If there is no obvious way to do so, click +on "More info" on the error message that shows up and then on "Run anyway".

+
+
+
+

You need to have Rust and Cargo installed. If you don't have, you can use +rustup to get them onto your machine.

+

Afterwards you can install Rye via cargo:

+
cargo install --git https://github.com/mitsuhiko/rye rye
+
+
+
+
+ +

For the next steps or ways to customize the installation, head over to the detailed +installation guide.

+
+ + + + + + + + +
+
+ + + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/philosophy/index.html b/philosophy/index.html new file mode 100644 index 0000000000..7e8c11d0c4 --- /dev/null +++ b/philosophy/index.html @@ -0,0 +1,1266 @@ + + + + + + + + + + + + + + + + + + + + + + Philosophy - Rye + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + + +
+
+
+ + + + +
+
+ + + + + + + + + + + + +

Philosophy and Vision

+

Rye was built to solve my problems. Here is what was +on my mind when I built it:

+
    +
  • +

    Virtualenvs: while I personally do not like virtualenvs that much, they are + so widespread and have reasonable tooling support, so I chose this over + __pypackages__.

    +
  • +
  • +

    No Default Dependencies: the virtualenvs when they come up are completely void + of dependencies. Not even pip or setuptools are installed into it. Rye + manages the virtualenv from outside the virtualenv.

    +
  • +
  • +

    No Core Non Standard Stuff: Rye (with the exception of it's own tool section + in the pyproject.toml) uses standardized keys. That means it uses regular + requirements as you would expect. It also does not use a custom lock file + format and uses pip-tools behind the scenes.

    +
  • +
  • +

    No Pip: Rye uses pip, but it does not expose it. It manage dependencies in + pyproject.toml only.

    +
  • +
  • +

    No System Python: I can't deal with any more linux distribution weird Python + installations or whatever mess there is on macOS. I used to build my own Pythons + that are the same everywhere, now I use indygreg's Python builds. + Rye will automatically download and manage Python builds from there. No compiling, + no divergence.

    +
  • +
  • +

    Project Local Shims: Rye maintains a python shim that auto discovers the + current pyproject.toml and automatically operates below it. Just add the + shims to your shell and you can run python and it will automatically always + operate in the right project.

    +
  • +
+

What Could Be?

+

There are a few shortcomings in the Python packaging world, largely as a result of +lack of standardization. Here is what this project ran into over the years:

+
    +
  • +

    No Python Binary Distributions: CPython builds from python.org are completely + inadequate. On some platforms you only get an .msi installer, on some you + literally only get tarballs. The various Python distributions that became popular + over the years are diverging greatly and cause all kinds of nonsense downstream. + This is why this Project uses the indygreg standalone builds. I hope that with + time someone will start distributing well maintained and reliable Python builds + to replace the mess we are dealing with today.

    +
  • +
  • +

    No Dev Dependencies: Rye currently needs a custom section in the pyproject.toml + to represent dev dependencies. There is no standard in the ecosystem for this. It + really should be added.

    +
  • +
  • +

    No Local Dependency Overlays: There is no standard for how to represent local + dependencies. Rust for this purpose has something like { path = "../foo" } + which allows both remote and local references to co-exist and it rewrites them + on publish.

    +
  • +
  • +

    No Exposed Pip: pip is intentionally not exposed. If you were to install something + into the virtualenv, it disappears next time you sync. If you symlink rye to + ~/.rye/shims/pip you can get access to pip without installing it into the + virtualenv. There be dragons.

    +
  • +
  • +

    No Workspace Spec: for monorepos and things of that nature, the Python ecosystem + would need a definition of workspaces. Today that does not exist which forces every + tool to come up with it's own solutions to this problem.

    +
  • +
  • +

    No Basic Script Section: There should be a standard in pyproject.toml to + represent scripts like rye does in rye.tools.scripts.

    +
  • +
+

The Vision

+

This describes of what I envision Python packaging and project management could +look like in an ideal world:

+

The Rust Experience

+

Coming from a Rust environment there are two tools which work together: rustup and +cargo. The first one of those is used to ensure that you have the correct Rust +toolchain on your machine. Rust greatly prefers binary distributions of the language +from the official website over external distributions.

+

cargo is the main entry point to development in Rust. It acts as the tool to +trigger test runs, start the build process, shell out to the documentation building +tool, linters but also things such as workspace management, dependency management and +package publishing.

+

Crucially a very important aspect of the Rust development experience is the strong +commitment to semver and the built-in support for it. This goes very deep. The +resolver for instance will deduplicate matching dependencies throughout the graph. +This means that if four libraries depend on libc@0.2, they will all resolve to +that dependency. However if another need arises for libc@1.0, then it's possible +for the dependency graph to result in both being loaded!

+

The ecosystem greatly depends on this. For instance when a new major release is made +of a very core library, in some cases extra care is taken to unify the now incompatible +versions by re-exporting core types from the newer to the older version. Thus it's +for instance possible for important-lib@0.2.32 to depend on +important-lib@1.0 internally so it can make the transition easier.

+

Additionally Rust heavily leverages lockfiles. Whenever you compile, the dependencies +are locked in place and future builds reuse the same dependency versions unless you +update.

+

Most importantly though the Rust ecosystem has embraced rustup and cargo that the +vast majority of people are using these tools on a daily basis. Even developers who +pick other tools like buck, are still using cargo regularly.

+

Going Python

+

Rye wants to explore if such an experience is possible with Python. I believe it can! +There is quite a lot of the ecosystem that can be leveraged for this purpose but there +is even more that would need to be built.

+

Important note: when you read "rye" in the context of the document it talks about +what a potential tool like rye could be. It might as well be that one of the many +tools that exist today, turn into that very tool that is described here.

+

My sentiment is that unless "the one tool" can emerge in the Python world, the +introduction of yet another tool might be a net-negative to the ecosystem. Plenty of +tools have been created over the years, and unfortunately it hasn't been able to +rally the majority of the Python community behind any tool. I do however believe it is +possible.

+

Bootstrapping Python

+

I believe the right approach is that >95% of users get a Python distribution via rye +and not to have rye pick up a system installed Python distribution. There are good +reasons for using a system Python installation, but it should be the exception not the +rule. Most importantly because a Python distribution that rye puts in place can be +made to have reliable and simple rules that do not differ between systems.

+

A huge cause of confusion and user frustration currently comes from Linux distribution +specific patches on top of Python that break tools and change behavior, particularly +in the python packaging ecosystem.

+

Bootstrapping Python via an independent tool has other benefits as well. It for instance +allows much easier cross-python version testing via tox or CI.

+

What needs to be done:

+
    +
  • Provide widely available Python builds, with largely standardized structure + retrievable from the internet. PEP 711 is a step + in that direction.
  • +
+

A Stronger Resolver

+

Today there are a ton of different resolvers in the Python ecosystem. Pip has two, poetry +has one, pdm has one, different independent Python and Rust resolvers exist on top of that. +Resolvers are important, but unfortunately are are both too many and too many issues with +the existing ones. Here is what I believe a resolver needs to be able to accomplish:

+
    +
  • +

    Allow resolving across markers: most resolvers in the Python ecosystem today can only + resolve for the current interpreter and platform (eg: pip, pip-tools). This means it cannot + create a resolution that is equally valid for a different platform. In part this is + a problem because of how environment markers in Python are defined. They allow a level of + expressiveness that cannot be reflected by most tools, however a subset could be supported.

    +
  • +
  • +

    Multi-version resolution support: this is a bit foreshadowing, but I believe for a + variety of reasons it needs to be possible for a resolver to not unify all requirements + to a single version, but to support multiple independent resolutions across major versions + of libraries. A future resolver should be able to permit package==2.0 and package==1.1 + to both be resolved for different parts of the tree.

    +
  • +
  • +

    Resolver API: access to the resolver is important. For editor plugins, or custom + tools it's always necessary to be able to resolve packages. For instance if you want + something as trivial as "add latest supported version of 'flask' to my pyproject.toml" + you need to be able to work with the resolver.

    +
  • +
  • +

    Filters: I strongly believe that a good resolver also needs a filter on top. For + instance it must be possible for a developer to restrict the resolver to stay within the + bounds of the target Python version and to never upgrade into a tree containing Python + versions that are too new. Likewise for supply chain safety a resolver should be able to + restrict itself to a set of vetted dependencies.

    +
  • +
+

What needs to be done:

+
    +
  • Create a reusable resolver that can be used by multiple tools in the ecosystem.
  • +
  • Make the resolver work with the proposed metadata cache
  • +
  • Expose the resolver as API for multiple tools to use.
  • +
  • Add a policy layer into the resolver that can be used to filter down the dependencies + before use.
  • +
+

Metadata Caches

+

Because of the rather simplistic nature of Python packages and package indexes a resolver +will always be restricted by the metadata that it can reliably pull. This is particularly +bad if the system needs to fall back to sdist uploads which in the worst case requires +executing python code to determine the dependencies, and those dependencies might not even +match on different platforms.

+

However this is a solvable problem with sufficient caching, and with the right design for +the cache, this cache could be shared. It might even be quite interesting for PyPI to +serve up "fake" metadata records for popular sdist only packages to help resolvers. +This might go a long way in improving the quality of the developer experience.

+

What needs to be done:

+
    +
  • Local metadata caches are added for the resolver to use
  • +
  • PyPI gains the ability to serve dependency meta data
  • +
+

Lockfiles

+

It's unclear if a standard can emerge for lock files given the different requirements, but a +Python packaging solution needs to have support for these. There are a lot of different +approaches to lockfiles today (poetry and pdm for instance have them) but it's not entirely +clear to me that the way they are handled today is sufficiently pragmatic to enable a tool +that is based on lockfiles to get majority adoption.

+

The reason in part relates the suboptimal situation with resolvers (eg: large projects can +take ten minutes or longer to dependency check in poetry), on the other hand however also +because of the reality of how dependencies are currently declared. For instance certain +libraries will "over" depend on third party libraries, even if they are not needed for a +developer. These pulled in dependencies however will still influence the resolver.

+

Most importantly a good lockfile also covers platforms other than the current developer's +machine. This means that if a project supports Windows and Linux, the lockfile should be +handling either dependency trees. This is what cargo accomplishes today, but cargo has a +a much simpler problem to solve here because it has perfect access to package metadata which +resolvers in Python do not have today. What is also problematic in Python is that certain +parts of the dependency tree can be version dependent. In Rust a library A either depends +on library B or it does not, but it does not depend on it conditional to a Python version.

+

The total expressiveness of Python dependencies is challenging. The lack of good metadata +access for the resolver combined with the ability to make dependencies optional conditional +to the Python version is tricky by itself. The complexity however is compounded by the +fact that the resolver needs to come to a solution that can only result in a single resolved +version per package.

+

What needs to be done:

+
    +
  • Experiment with a restricted lock format that satisfies a subset of what markers provide + today, that strikes a good balance.
  • +
  • Provide lockfile support as part of the resolver library.
  • +
+

Upper Bounds & Multi Versioning

+

Resolving Python dependencies is particularly challenging because a single solution must be +found per package. A reason this works at all in the Python ecosystem is that most libraries +do not set upper bounds. This means that they will be eagerly accepting future libraries even +at the cost of not supporting them. That's largely possible because Python is a dynamic +language and a lot of flexibility is usually possible here. However with increased utilization +of type information in the Python world, and maybe with stronger desires for proper locking, +it might be quite likely that upper version bounds become more common.

+

Once that happens however, the Python ecosystem will quite quickly run into blocking future +upgrades until the entire dependency graph has moved up which creates a lot of friction. +Other ecosystems have solved this problem by strictly enforcing semver semantics onto packages +and by permitting multiple semver incompatible libraries to be loaded simultaneously. While +usually a library is only allowed to permit on a single version of a dependency, that dependency +can exist in different versions throughout the dependency tree.

+

In Python there is a perceived worry that this cannot be accomplished because of how site-packages, +PYTHONPATH and sys.modules works. However I believe these to be solvable issues. On the one +hand because .pth files can be used to completely change how the import system works, secondly +because the importlib.metadata API is strong enough these days to allow a package to resolve +it's own metadata. The combination of the two can be used to "redirect" imports in sys.modules +and import statements to ensure that if a library imports a dependency of itself, it ends up with +the right version.

+

What needs to be done:

+
    +
  • Add a new metadata key to pyproject.toml that declares that a package supports multi-versioning
  • +
  • Enforce semver semantics on multi-version dependencies
  • +
  • Provide an import hook that provides multi-version imports as part of Rye
  • +
  • Relax the resolver to permit multiple solutions for multi-version dependencies
  • +
+

Workspaces and Local / Multi Path References

+

With growing development teams one of the most frustrating experiences is the inability to +break up a monolithic Python module into smaller modules without having to constantly publish +minor versions to a package index. The way the Rust ecosystem deals with this issue is two-fold: +on the one hand Rust supports workspaces natively. Workspaces share dependencies and the +resolver results. The equivalent in Python would be that a workspace shares a virtualenv +across all of the projects within in. The second way in which Rust solves this problem is +to permit a dependency to both support declaration of the package name, index but also local +reference.

+

While also Rust does not permit a crate to be published to a package index with references to +packages outside of the index, a separate rewrite step kicks in ahead of publish to clean out +invalid dependency references. If no valid reference remains, the package will not publish.

+

What needs to be done:

+
    +
  • requirement declarations need to be expanded to support defining the name of the index where + they can be found, and optional local path references.
  • +
+

Every Project in a Virtualenv

+

While virtualenv is not my favorite tool, it's the closest we have to a standard. I proposed +that there is always one path for a virtualenv .venv and when Rye manages it, users should +not interact with it manually. It's at that point rye's responsibility to manage it, and it +shall manage it as if it was a throw-away, always re-creatable scratch-pad for dependencies.

+

Preferably over time the structure of virtualenvs aligns between different Python versions +(eg: Windows vs Linux) and the deeply nested lib/py-ver/site-packages structure is flattened +out.

+

What needs to be done:

+
    +
  • Agree on a name for where managed virtualenvs are placed (eg: .venv in the workspace root)
  • +
+

Dev and Tool Dependencies

+

Another topic that is currently unresolved across tools in the ecosystem is how to work with +dependencies that are not used in production. For instance it's quite common that a certain +dependency really only matters on the developer's machine. Today pdm and some other tools +have custom sections in the pyproject.toml file to mark development dependencies, but there +is no agreement across tools on it.

+

What needs to be done:

+

There needs to be an agreed upon standard for all tools. See this discussion

+

Opinionated Defaults

+

Python against PEP-8's wishes just has too many ways in which things can be laid out. There +should be a much stronger push towards encouraging common standards:

+

What needs to be done:

+
    +
  • Rye shall ship with the one true formatter
  • +
  • Rye shall ship with the one true linter
  • +
  • Rye shall always create a preferred folder structure for new projects
  • +
  • Rye shall loudly warn if package-foo does not provide a package_foo module
  • +
+

Existing Tools

+

Some of the existing tools in the ecosystem are close, and there is a good chance that some +of these might be able to combine forces to create that one-true tool. I hope that there +is enough shared interest, that we don't end up with three tools that all try to be Rye.

+ + + + + + +
+
+ + + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/search/search_index.json b/search/search_index.json new file mode 100644 index 0000000000..3c596b1039 --- /dev/null +++ b/search/search_index.json @@ -0,0 +1 @@ +{"config":{"lang":["en"],"separator":"[\\s\\-]+","pipeline":["stopWordFilter"]},"docs":[{"location":"","title":"Rye: An Experimental Package Management Solution for Python","text":"

Rye is Armin's personal one-stop-shop for all his Python needs. It installs and manages Python installations, helps working with pyproject.toml files, installs and uninstalls dependencies, creates and updates virtualenvs behind the scenes. It supports monorepos and global tool installations.

Rye is an experimental endeavour to build a new type of packaging experience to Python inspired by rustup and cargo from Rust. It's not yet production ready but feedback and suggestions are greatly appreciated.

Star Discuss Sponsor

Installation Instructions

LinuxmacOSWindowsCompile Yourself

To install run you can curl a command which will install the right binary for your operating system and CPU architecture and install it:

curl -sSf https://rye-up.com/get | bash\n

Alternatively if you don't trust this approach, you can download the latest release binary. On first run it will install itself.

  • rye-x86_64-linux.gz for 64bit Intel computers
  • rye-aarch64-linux.gz for 64bit ARM computers
gunzip rye-x86_64-linux.gz\nchmod +x ./rye-x86_64-linux\n./rye-x86_64-linux\n

To install run you can curl a command which will install the right binary for your operating system and CPU architecture and install it:

curl -sSf https://rye-up.com/get | bash\n

Alternatively if you don't trust this approach, you can download the latest release binary. On first run it will install itself.

  • rye-aarch64-macos.gz for M1/M2 Macs
  • rye-x86_64-macos.gz for Intel Macs
gunzip rye-aarch64-macos.gz\nchmod +x ./rye-aarch64-macos\n./rye-aarch64-macos\n

To install Rye on windows download the latest release and run the binary. Upon first run it will install itself. Please note that it's strongly recommended to have \"Developer Mode\" activated when using Rye and before starting the installation. Learn more.

  • rye-x86_64-windows.exe for 64bit Intel Windows
  • rye-x86-windows.exe for 32bit Intel Windows

Note

Rye does not yet use signed binaries which means that you will need to allow the execution of the downloaded executable. If there is no obvious way to do so, click on \"More info\" on the error message that shows up and then on \"Run anyway\".

You need to have Rust and Cargo installed. If you don't have, you can use rustup to get them onto your machine.

Afterwards you can install Rye via cargo:

cargo install --git https://github.com/mitsuhiko/rye rye\n

For the next steps or ways to customize the installation, head over to the detailed installation guide.

"},{"location":"changelog/","title":"Changelog","text":"

Here you can find all the released changes to Rye. If you want to also see the in-development changes that were not released yet, refer to the CHANGELOG.md file in the repository.

"},{"location":"changelog/#0170","title":"0.17.0","text":"

Released on 2024-01-15

  • Fixed default generated script reference. #527

  • Correctly fall back to home folder if HOME is unset. #533

"},{"location":"changelog/#0160","title":"0.16.0","text":"

Released on 2023-12-17

  • By default a script with the name of the project is now also configured. #519

  • Rye now configures hatchling better in rye init so that it works with hatchling 1.19 and later. #521

  • Rye now detects the dummy Python shim that starts the windows store and refuses to consider it. #486

"},{"location":"changelog/#0152","title":"0.15.2","text":"

Released on 2023-10-04

  • Fixed the updater not replacing the python shim correctly on Linux.
"},{"location":"changelog/#0151","title":"0.15.1","text":"

Released on 2023-10-03

  • Fixed the updater not replacing the python3 shim correctly.
"},{"location":"changelog/#0150","title":"0.15.0","text":"

Released on 2023-10-03

  • Added support for Python 3.12. #462
"},{"location":"changelog/#0140","title":"0.14.0","text":"

Released on 2023-10-01

  • Add support for fetching alternative CPU architectures. #447

  • The order of git submodule initialization was changed. This improves the automatic author detection when includeIf is used. #443

  • The linux shim installer code will no longer fall back to symlinks when a hardlink cannot be created. This is done as a symlinked shim will not ever function correctly on Linux. This prevents the shim executables like python to instead act as if they are rye. The fallback behavior is now to copy the executable instead. #441

  • The installer now detects fish and will spit out additional instructions for configuring the shell.

  • Fix the wrong behavior when bump version. #454

"},{"location":"changelog/#0130","title":"0.13.0","text":"

Released on 2023-08-29

  • Add a python3 shim on windows. Previously entering python3 in the command line would always bring up the windows store python proxy even when global shims were enabled. As virtualenvs do not support the python3 executable on windows, the internal shim handling is now also changed so that trying to launch python3 will fall back to python. This makes it possible to run maturin build.

  • Add maturin build command to start a new maturin PyO3 project.

"},{"location":"changelog/#0120","title":"0.12.0","text":"

Released on 2023-08-27

  • Improve handling of the pth files for TCL on pypy. #409

  • The rye tools list command now accepts -v to also print out the versions of the installed tools. #396

  • Fixed parsing of versions by rye version. #397

  • Improved the help message for rye init. #401

  • The email address now defaults to a syntactically valid email address if not known to prevent errors with some build tools.

  • Added new Python versions.

  • The rye installer now detects NOEXEC temporary folders and prints out a more helpful error message. #394

  • Fixed an issue where the author email was incorrectly detected. #382

  • The prompt of new virtualenvs is now set to the project name. #383

"},{"location":"changelog/#0110","title":"0.11.0","text":"

Released on 2023-07-18

  • Added new Python versions.

  • Added a new config key default.author to configure the default author that should be set. This overrides the default author that is normally loaded from the git config. #377

  • When importing with rye init and no src folder exists, it will not be created. #375

  • Added support for shell command on Windows. #363

  • Pin down pip to an older version to avoid issues with an incompatible pip-tools version. This does not yet update pip-tools to 7.0 as there are significant regressions in 7.x. #374

  • The version command can show dynamic versions now. #355

  • rye add now properly checks some incompatible argument combinations. #347

  • There is now more toolchain validation. This better supports cases where rye was interrupted during sync. #351

"},{"location":"changelog/#0100","title":"0.10.0","text":"

Released on 2023-07-07

  • Fixed a bug with rye init not operating correctly due to a argument conflict. #346

  • Scripts now support a PDM style call script type. #345

  • The init command is now capable of importing existing projects. #265

  • Fixed the global shim behavior on Windows. #344

"},{"location":"changelog/#090","title":"0.9.0","text":"

Released on 2023-06-21

  • The internal Rye Python version is now 3.11.

  • Rye now emits most messages, most of the time to stdout rather than stderr. #342

  • rye add now accepts --pin to let one override the type of pin to use. #341

  • Added rye config to read and manipulate the config.toml file. #339

  • Added support for the new behavior.global-python flag which turns on global Python shimming. When enabled then the python shim works even outside of Rye managed projects. Additionally the shim (when run outside of Rye managed projects) supports a special first parameter +VERSION which requests a specific version of Python (eg: python +3.8 to request Python 3.8). #336

  • Renamed the config key default.dependency_operator to default.dependency-operator and behavior.force_rye_managed to behavior.force-rye-managed. #338

"},{"location":"changelog/#080","title":"0.8.0","text":"

Released on 2023-06-18

  • Rye for now prefers >= over ~= for newly added dependencies.

  • The workspace member declaration is now platform independent. If members is now explicitly set to an empty list it will not fall back to auto discovery. #331

  • rye add now pins versions with == instead of ~= when the version of the package does not use at least two components. This means that for instance it will now correctly use openai-whisper==20230314 rather than openai-whisper~=20230314 which is not actually satisfiable. #328

  • rye install now lets you install dependencies into the tool's virtualenv during installation that are undeclared via the new --extra-requirement option. #326

  • Improved handling of relative path installations by setting PROJECT_ROOT the same way as PDM does. #321

  • Workspaces will now never discover pyproject.toml files in any dot directories. (Name starting with .) #329

  • Fixed rye build not working correctly on Windows. #327

"},{"location":"changelog/#070","title":"0.7.0","text":"

Released on 2023-06-12

  • rye sync and rye lock now accept --pyproject. #296

  • Added JSON output to rye toolchain list by adding --format=json. #306

  • rye version can bump version by --bump option now. #298

  • Fixed members not handled correctly in workspaces. #300

  • Add --clean for build command. #297

  • Fixed an issue where pip was not invoked from the right working directory causing issues for workspace installations. #292

  • rye init now accepts --private to set the Private :: Do Not Upload classifier that prevents uploads to PyPI. #291

"},{"location":"changelog/#060","title":"0.6.0","text":"

Released on 2023-06-03

  • Add version subcommand for rye. #285

  • Fixed rye pin pinning the wrong version. #288

  • Calling rye init on the root directory no longer fails. #274

  • rye run, show, pin, shell and build now take a --pyproject argument. #232

"},{"location":"changelog/#050","title":"0.5.0","text":"

Released on 2023-05-31

  • Rye will no longer enforce a downloaded interpreter for the internal toolchain. If one has been registered that is compatible it will be used. Additionally the installer now supports the RYE_TOOLCHAIN environment variable which allows a user to supply an already existing Python interpreter at install time. #267

  • The publish command now supports --yes to disable prompts. #270

  • When a Python debug build (Py_DEBUG) is registered as custom toolchain, -dbg is automatically appended to the name by default. #269

  • lto+pgo builds are now preferred for the Python toolchain builds when available. #268

  • It's now possible for .python-version to request partial Python versions in which case the latest available is used. In particular this means that a version like 3.10 can be written into .python-version rather than 3.10.11. This can be accomplished by invoking pin with the new --relaxed flag. #255

  • Workspaces will no longer discover pyproject.toml files in virtualenvs or .git folders. #266

  • Adding or removing dependencies with add or remove now reformats the dependencies array in the pyproject.toml file to multi-line with trailing commas. This should result in significantly better diffing behavior out of the box. #263

  • Default build-system and license can be specified in global config. #244

  • Fixed an issue where the init command would not let you create flit based projects. #254

  • Resolve an error (\"No such file or directory\") shown after updates on Linux machines. #252

  • The built-in updater now validates checksums of updates when updates have SHA-256 hashes available. #253

  • init now accepts --no-pin to not create a .python-version file. #247

"},{"location":"changelog/#040","title":"0.4.0","text":"

Released on 2023-05-29

  • Releases starting with 0.4.0 onwards are published with SHA256 checksum files for all release assets. These files are not yet validated by the installer or updater however.

  • The install command can now install tools from custom indexes. #240

  • Virtualenvs on Unix are now created with a hack to pre-configure TCL and TKinter. #233

  • Fix invalid version error when using rye init with custom toolchain. #234

  • Failed tool installations now properly clean up. #225

  • Correctly swap the rye executable on windows when performing an update to a git version via self update.

"},{"location":"changelog/#030","title":"0.3.0","text":"

Released on 2023-05-27

  • Support retrieving username and repository-url from credentials if not provided for the publish command. #217

  • The installer now validates the availability of shared libraries on Linux with ldd and emits an error with additional information if necessary shared libraries are missing. #220

  • It's now possible to configure http and https proxies. #215

  • If a package is not found because it only has matching pre-releases, a warning is now printed to tell the user to pass --pre. #218

  • Add --username parameter for rye publish. #211

  • The shims are now more resilient. Previously a pyproject.toml file caused in all cases a virtualenv to be created. Now this will only happen when the rye.tool.managed flag is set to true. The old behavior can be forced via the global config. #212

"},{"location":"changelog/#020","title":"0.2.0","text":"

Released on 2023-05-23

  • Resolved a bug where on Windows hitting the shift key (or some other keys) in confirm prompts would cause an error.

  • The installer on Windows now warns if symlinks are not enabled and directs the user to enable developer mode. The --version output now also shows if symlinks are available. #205

  • Support auto fix requires-python when there is a conflict. #160

  • Added support for custom indexes. #199

  • rye add no longer complains when a local version information is in the version. #199

"},{"location":"changelog/#012","title":"0.1.2","text":"

Released on 2023-05-22

  • Fixed dev-dependencies not being installed when using workspace. #170

  • init no longer creates invalid flit config. #195

  • Support direct references when adding a package. #158

  • Fixed a bug with uninstall on Unix platforms. #197

"},{"location":"changelog/#011","title":"0.1.1","text":"

Released on 2023-05-18

  • The installer on windows will now ask for a key to be pressed so it does not close the window without information. #183

  • Fixed an issue on macOS where the installer would die with \"os error 24\" when directly piped to bash. #184

"},{"location":"changelog/#010","title":"0.1.0","text":"

Released on 2023-05-17

  • Rye now comes with binary releases for some platforms.

  • A new self uninstall command was added to uninstall rye and the new self update command updates to the latest release version.

  • Rye now includes a publish command for publishing Python packages to a package repository. #86

  • Script declarations in pyproject.toml now permit chaining and custom environment variables. #153

  • Added tools install and tools uninstall as aliases for install and uninstall and added tools list to show all installed tools.

  • Rye is now capable of downloading a selected set of PyPy releases. To do so use rye pin pypy@3.9.16 or any other supported PyPy release.

  • Custom cpython toolchains are now registered just as cpython rather than custom-cpython.

  • Rye now supports Python down to 3.7.

  • Rye's self command now includes a completion subcommand to generate a completion script for your shell.

  • The downloaded Python distributions are now validated against the SHA-256 hashes.

  • Rye now builds on windows. This is even more experimental though than support for Linux and macOS.

  • Added --features and --all-features for lock and sync.

  • Rye will now look at the RYE_HOME to determine the location of the .rye folder. If it's not set, $HOME/.rye is used as before.

  • Rye now has a most consistent handling for virtualenv versions. If .python-version is provided, that version is used. Otherwise if requires-python is set in the pyproject.toml, that version is used instead. When a new project is created the .python-version file is written and the current latest cpython version is picked.

  • It's now possible to explicitly set the name of the project when initializing a new one.

  • Rye's init command now attempts to initialize projects with git and will automatically create a src/project_name/__init__.py file.

  • Rye can now also generate a license text when initializing projects.

  • Rye now supports negative (exclusion) dependencies. These can be used to prevent a dependency from installing, even if something else in the graph depends on it. Use rye add --exclude package-name to add such a dependency.

  • sync now accepts --no-lock to prevent updating the lock file.

  • Rye's add command now accepts a --pre parameter to include pre-release.

  • Rye's pin command now updates the pyproject.toml requires-python.

  • Rye's install command now accepts a --include-dep parameter to include scripts from one or more given dependencies.

  • Rye now honors requires-python in the add command. This means the the initial resolution will not pick a version higher than what's supported by the lower boundary.

  • When installing packages as global tools, a warning is now emitted if there were no scripts in the package. Additionally installing packages from local paths and zip files is now supported.

  • A rye self update command was added to compile and install the latest version via cargo.

  • Added more convenient ways to install from git/urls by supplying a --git or --url parameter. This will behind the scenes format a PEP 508 requirement string.

  • Added a shell command which will spawn a shell with the virtualenv activated.

  • Added a make-req command to conveniently format out PEP 508 requirement strings from parts.

  • The internal virtualenv used to manage pip-tools and other libraries now automatically updates when necessary.

  • rye toolchain register can now be used to register a local python installation as toolchain with rye.

  • rye build was added to allow building sdist and bdist_wheel distributions.

  • Rye now correctly handles whitespace in folder names.

"},{"location":"community/","title":"Community","text":"

Rye is a new project and feedback is greatly appreciated. Lots of it. Because of this there are various different ways in which you can engage with either the developer or other members of the community:

  • Discussion Forum, to discuss the project on GitHub
  • Discord, for conversations with other developers in text form
  • Issue Tracker, if you run into bugs or have suggestions

You can also reach out via Twitter or Bluesky.

"},{"location":"philosophy/","title":"Philosophy and Vision","text":"

Rye was built to solve my problems. Here is what was on my mind when I built it:

  • Virtualenvs: while I personally do not like virtualenvs that much, they are so widespread and have reasonable tooling support, so I chose this over __pypackages__.

  • No Default Dependencies: the virtualenvs when they come up are completely void of dependencies. Not even pip or setuptools are installed into it. Rye manages the virtualenv from outside the virtualenv.

  • No Core Non Standard Stuff: Rye (with the exception of it's own tool section in the pyproject.toml) uses standardized keys. That means it uses regular requirements as you would expect. It also does not use a custom lock file format and uses pip-tools behind the scenes.

  • No Pip: Rye uses pip, but it does not expose it. It manage dependencies in pyproject.toml only.

  • No System Python: I can't deal with any more linux distribution weird Python installations or whatever mess there is on macOS. I used to build my own Pythons that are the same everywhere, now I use indygreg's Python builds. Rye will automatically download and manage Python builds from there. No compiling, no divergence.

  • Project Local Shims: Rye maintains a python shim that auto discovers the current pyproject.toml and automatically operates below it. Just add the shims to your shell and you can run python and it will automatically always operate in the right project.

"},{"location":"philosophy/#what-could-be","title":"What Could Be?","text":"

There are a few shortcomings in the Python packaging world, largely as a result of lack of standardization. Here is what this project ran into over the years:

  • No Python Binary Distributions: CPython builds from python.org are completely inadequate. On some platforms you only get an .msi installer, on some you literally only get tarballs. The various Python distributions that became popular over the years are diverging greatly and cause all kinds of nonsense downstream. This is why this Project uses the indygreg standalone builds. I hope that with time someone will start distributing well maintained and reliable Python builds to replace the mess we are dealing with today.

  • No Dev Dependencies: Rye currently needs a custom section in the pyproject.toml to represent dev dependencies. There is no standard in the ecosystem for this. It really should be added.

  • No Local Dependency Overlays: There is no standard for how to represent local dependencies. Rust for this purpose has something like { path = \"../foo\" } which allows both remote and local references to co-exist and it rewrites them on publish.

  • No Exposed Pip: pip is intentionally not exposed. If you were to install something into the virtualenv, it disappears next time you sync. If you symlink rye to ~/.rye/shims/pip you can get access to pip without installing it into the virtualenv. There be dragons.

  • No Workspace Spec: for monorepos and things of that nature, the Python ecosystem would need a definition of workspaces. Today that does not exist which forces every tool to come up with it's own solutions to this problem.

  • No Basic Script Section: There should be a standard in pyproject.toml to represent scripts like rye does in rye.tools.scripts.

"},{"location":"philosophy/#the-vision","title":"The Vision","text":"

This describes of what I envision Python packaging and project management could look like in an ideal world:

"},{"location":"philosophy/#the-rust-experience","title":"The Rust Experience","text":"

Coming from a Rust environment there are two tools which work together: rustup and cargo. The first one of those is used to ensure that you have the correct Rust toolchain on your machine. Rust greatly prefers binary distributions of the language from the official website over external distributions.

cargo is the main entry point to development in Rust. It acts as the tool to trigger test runs, start the build process, shell out to the documentation building tool, linters but also things such as workspace management, dependency management and package publishing.

Crucially a very important aspect of the Rust development experience is the strong commitment to semver and the built-in support for it. This goes very deep. The resolver for instance will deduplicate matching dependencies throughout the graph. This means that if four libraries depend on libc@0.2, they will all resolve to that dependency. However if another need arises for libc@1.0, then it's possible for the dependency graph to result in both being loaded!

The ecosystem greatly depends on this. For instance when a new major release is made of a very core library, in some cases extra care is taken to unify the now incompatible versions by re-exporting core types from the newer to the older version. Thus it's for instance possible for important-lib@0.2.32 to depend on important-lib@1.0 internally so it can make the transition easier.

Additionally Rust heavily leverages lockfiles. Whenever you compile, the dependencies are locked in place and future builds reuse the same dependency versions unless you update.

Most importantly though the Rust ecosystem has embraced rustup and cargo that the vast majority of people are using these tools on a daily basis. Even developers who pick other tools like buck, are still using cargo regularly.

"},{"location":"philosophy/#going-python","title":"Going Python","text":"

Rye wants to explore if such an experience is possible with Python. I believe it can! There is quite a lot of the ecosystem that can be leveraged for this purpose but there is even more that would need to be built.

Important note: when you read \"rye\" in the context of the document it talks about what a potential tool like rye could be. It might as well be that one of the many tools that exist today, turn into that very tool that is described here.

My sentiment is that unless \"the one tool\" can emerge in the Python world, the introduction of yet another tool might be a net-negative to the ecosystem. Plenty of tools have been created over the years, and unfortunately it hasn't been able to rally the majority of the Python community behind any tool. I do however believe it is possible.

"},{"location":"philosophy/#bootstrapping-python","title":"Bootstrapping Python","text":"

I believe the right approach is that >95% of users get a Python distribution via rye and not to have rye pick up a system installed Python distribution. There are good reasons for using a system Python installation, but it should be the exception not the rule. Most importantly because a Python distribution that rye puts in place can be made to have reliable and simple rules that do not differ between systems.

A huge cause of confusion and user frustration currently comes from Linux distribution specific patches on top of Python that break tools and change behavior, particularly in the python packaging ecosystem.

Bootstrapping Python via an independent tool has other benefits as well. It for instance allows much easier cross-python version testing via tox or CI.

What needs to be done:

  • Provide widely available Python builds, with largely standardized structure retrievable from the internet. PEP 711 is a step in that direction.
"},{"location":"philosophy/#a-stronger-resolver","title":"A Stronger Resolver","text":"

Today there are a ton of different resolvers in the Python ecosystem. Pip has two, poetry has one, pdm has one, different independent Python and Rust resolvers exist on top of that. Resolvers are important, but unfortunately are are both too many and too many issues with the existing ones. Here is what I believe a resolver needs to be able to accomplish:

  • Allow resolving across markers: most resolvers in the Python ecosystem today can only resolve for the current interpreter and platform (eg: pip, pip-tools). This means it cannot create a resolution that is equally valid for a different platform. In part this is a problem because of how environment markers in Python are defined. They allow a level of expressiveness that cannot be reflected by most tools, however a subset could be supported.

  • Multi-version resolution support: this is a bit foreshadowing, but I believe for a variety of reasons it needs to be possible for a resolver to not unify all requirements to a single version, but to support multiple independent resolutions across major versions of libraries. A future resolver should be able to permit package==2.0 and package==1.1 to both be resolved for different parts of the tree.

  • Resolver API: access to the resolver is important. For editor plugins, or custom tools it's always necessary to be able to resolve packages. For instance if you want something as trivial as \"add latest supported version of 'flask' to my pyproject.toml\" you need to be able to work with the resolver.

  • Filters: I strongly believe that a good resolver also needs a filter on top. For instance it must be possible for a developer to restrict the resolver to stay within the bounds of the target Python version and to never upgrade into a tree containing Python versions that are too new. Likewise for supply chain safety a resolver should be able to restrict itself to a set of vetted dependencies.

What needs to be done:

  • Create a reusable resolver that can be used by multiple tools in the ecosystem.
  • Make the resolver work with the proposed metadata cache
  • Expose the resolver as API for multiple tools to use.
  • Add a policy layer into the resolver that can be used to filter down the dependencies before use.
"},{"location":"philosophy/#metadata-caches","title":"Metadata Caches","text":"

Because of the rather simplistic nature of Python packages and package indexes a resolver will always be restricted by the metadata that it can reliably pull. This is particularly bad if the system needs to fall back to sdist uploads which in the worst case requires executing python code to determine the dependencies, and those dependencies might not even match on different platforms.

However this is a solvable problem with sufficient caching, and with the right design for the cache, this cache could be shared. It might even be quite interesting for PyPI to serve up \"fake\" metadata records for popular sdist only packages to help resolvers. This might go a long way in improving the quality of the developer experience.

What needs to be done:

  • Local metadata caches are added for the resolver to use
  • PyPI gains the ability to serve dependency meta data
"},{"location":"philosophy/#lockfiles","title":"Lockfiles","text":"

It's unclear if a standard can emerge for lock files given the different requirements, but a Python packaging solution needs to have support for these. There are a lot of different approaches to lockfiles today (poetry and pdm for instance have them) but it's not entirely clear to me that the way they are handled today is sufficiently pragmatic to enable a tool that is based on lockfiles to get majority adoption.

The reason in part relates the suboptimal situation with resolvers (eg: large projects can take ten minutes or longer to dependency check in poetry), on the other hand however also because of the reality of how dependencies are currently declared. For instance certain libraries will \"over\" depend on third party libraries, even if they are not needed for a developer. These pulled in dependencies however will still influence the resolver.

Most importantly a good lockfile also covers platforms other than the current developer's machine. This means that if a project supports Windows and Linux, the lockfile should be handling either dependency trees. This is what cargo accomplishes today, but cargo has a a much simpler problem to solve here because it has perfect access to package metadata which resolvers in Python do not have today. What is also problematic in Python is that certain parts of the dependency tree can be version dependent. In Rust a library A either depends on library B or it does not, but it does not depend on it conditional to a Python version.

The total expressiveness of Python dependencies is challenging. The lack of good metadata access for the resolver combined with the ability to make dependencies optional conditional to the Python version is tricky by itself. The complexity however is compounded by the fact that the resolver needs to come to a solution that can only result in a single resolved version per package.

What needs to be done:

  • Experiment with a restricted lock format that satisfies a subset of what markers provide today, that strikes a good balance.
  • Provide lockfile support as part of the resolver library.
"},{"location":"philosophy/#upper-bounds-multi-versioning","title":"Upper Bounds & Multi Versioning","text":"

Resolving Python dependencies is particularly challenging because a single solution must be found per package. A reason this works at all in the Python ecosystem is that most libraries do not set upper bounds. This means that they will be eagerly accepting future libraries even at the cost of not supporting them. That's largely possible because Python is a dynamic language and a lot of flexibility is usually possible here. However with increased utilization of type information in the Python world, and maybe with stronger desires for proper locking, it might be quite likely that upper version bounds become more common.

Once that happens however, the Python ecosystem will quite quickly run into blocking future upgrades until the entire dependency graph has moved up which creates a lot of friction. Other ecosystems have solved this problem by strictly enforcing semver semantics onto packages and by permitting multiple semver incompatible libraries to be loaded simultaneously. While usually a library is only allowed to permit on a single version of a dependency, that dependency can exist in different versions throughout the dependency tree.

In Python there is a perceived worry that this cannot be accomplished because of how site-packages, PYTHONPATH and sys.modules works. However I believe these to be solvable issues. On the one hand because .pth files can be used to completely change how the import system works, secondly because the importlib.metadata API is strong enough these days to allow a package to resolve it's own metadata. The combination of the two can be used to \"redirect\" imports in sys.modules and import statements to ensure that if a library imports a dependency of itself, it ends up with the right version.

What needs to be done:

  • Add a new metadata key to pyproject.toml that declares that a package supports multi-versioning
  • Enforce semver semantics on multi-version dependencies
  • Provide an import hook that provides multi-version imports as part of Rye
  • Relax the resolver to permit multiple solutions for multi-version dependencies
"},{"location":"philosophy/#workspaces-and-local-multi-path-references","title":"Workspaces and Local / Multi Path References","text":"

With growing development teams one of the most frustrating experiences is the inability to break up a monolithic Python module into smaller modules without having to constantly publish minor versions to a package index. The way the Rust ecosystem deals with this issue is two-fold: on the one hand Rust supports workspaces natively. Workspaces share dependencies and the resolver results. The equivalent in Python would be that a workspace shares a virtualenv across all of the projects within in. The second way in which Rust solves this problem is to permit a dependency to both support declaration of the package name, index but also local reference.

While also Rust does not permit a crate to be published to a package index with references to packages outside of the index, a separate rewrite step kicks in ahead of publish to clean out invalid dependency references. If no valid reference remains, the package will not publish.

What needs to be done:

  • requirement declarations need to be expanded to support defining the name of the index where they can be found, and optional local path references.
"},{"location":"philosophy/#every-project-in-a-virtualenv","title":"Every Project in a Virtualenv","text":"

While virtualenv is not my favorite tool, it's the closest we have to a standard. I proposed that there is always one path for a virtualenv .venv and when Rye manages it, users should not interact with it manually. It's at that point rye's responsibility to manage it, and it shall manage it as if it was a throw-away, always re-creatable scratch-pad for dependencies.

Preferably over time the structure of virtualenvs aligns between different Python versions (eg: Windows vs Linux) and the deeply nested lib/py-ver/site-packages structure is flattened out.

What needs to be done:

  • Agree on a name for where managed virtualenvs are placed (eg: .venv in the workspace root)
"},{"location":"philosophy/#dev-and-tool-dependencies","title":"Dev and Tool Dependencies","text":"

Another topic that is currently unresolved across tools in the ecosystem is how to work with dependencies that are not used in production. For instance it's quite common that a certain dependency really only matters on the developer's machine. Today pdm and some other tools have custom sections in the pyproject.toml file to mark development dependencies, but there is no agreement across tools on it.

What needs to be done:

There needs to be an agreed upon standard for all tools. See this discussion

"},{"location":"philosophy/#opinionated-defaults","title":"Opinionated Defaults","text":"

Python against PEP-8's wishes just has too many ways in which things can be laid out. There should be a much stronger push towards encouraging common standards:

What needs to be done:

  • Rye shall ship with the one true formatter
  • Rye shall ship with the one true linter
  • Rye shall always create a preferred folder structure for new projects
  • Rye shall loudly warn if package-foo does not provide a package_foo module
"},{"location":"philosophy/#existing-tools","title":"Existing Tools","text":"

Some of the existing tools in the ecosystem are close, and there is a good chance that some of these might be able to combine forces to create that one-true tool. I hope that there is enough shared interest, that we don't end up with three tools that all try to be Rye.

"},{"location":"guide/","title":"Introduction","text":"

Rye is still a very experimental tool, but this guide is here to help you get started. Before we dive into the installation and basic usage guide it's important for you to understand what Rye actually is.

Rye is a one-stop-shop tool. The idea is that as a Python developer all you need to know is Rye, because Rye is your start into the experience. As a Rye user you do not even need to install Python yourself as Rye does this for you. This means to use Rye, you just need to install Rye, the rest is done by Rye itself.

Once Rye is on your system, it can automatically install Python interpreters for you, install packages from package indexes, manage virtualenvs behind the scenes and more.

Interested? Then head over to Installation to learn about how to get Rye onto your system. Once that is done, read the Basics to learn about how Rye can be used.

"},{"location":"guide/basics/","title":"Basics","text":"

To use Rye you need to have a pyproject.toml based Python project. For this guide you can create one with rye init which will create a new folder with a new project inside:

rye init my-project\ncd my-project\n

The following structure will be created:

.\n\u251c\u2500\u2500 .git\n\u251c\u2500\u2500 .gitignore\n\u251c\u2500\u2500 .python-version\n\u251c\u2500\u2500 README.md\n\u251c\u2500\u2500 pyproject.toml\n\u2514\u2500\u2500 src\n    \u2514\u2500\u2500 my_project\n        \u2514\u2500\u2500 __init__.py\n

Good to Know

The init command accepts a lot of options to customize what it generates. Run rye init --help to see all the options available in the version you have installed.

A pyproject.toml is used to store metadata about your project as well as some Rye configuration. Most of Rye's commands will require a pyproject.toml to work. Note that Rye today does not support setup.py based projects. Note that when Rye initializes a project it also writes a .python-version file. This file contains the version number of the Python version that should be used for this project. It can be changed by running rye pin. For instance to tell Rye to use Python 3.10:

$ rye pin 3.10\n
"},{"location":"guide/basics/#first-sync","title":"First Sync","text":"

Once that is done, you can use rye sync to get the first synchronization. After that, Rye will have created a virtualenv in .venv and written lockfiles into requirements.lock and requirements-dev.lock.

rye sync\n

The virtualenv that Rye manages is placed in .venv next to your pyproject.toml. The first time you run this you will notice that Rye automatically downloaded and installed a compatible CPython interpreter for you. If you have already another Python installation on your system it will not be used! For more information about this behavior read about toolchains.

You can activate and work with it as normal with one notable exception: the Python installation in it does not contain pip. If you have correctly installed Rye with the shims enabled, after the sync you can run python and you will automatically be operating in that virtualenv, even if it's not enabled. You can validate this by printing out sys.prefix:

python -c \"import sys; print(sys.prefix)\"\n

It will print out the full path to the managed virtualenv.

"},{"location":"guide/basics/#adding-dependencies","title":"Adding Dependencies","text":"

Use the add command to add dependencies to your project.

rye add \"flask>=2.0\"\n

Note that after add you need to run sync again to actually install it. If you want to add packages from custom indexes, you have to configure the source first.

"},{"location":"guide/basics/#remove-a-dependency","title":"Remove a Dependency","text":"

Use the remove command to remove a dependency from the project again.

rye remove flask\n
"},{"location":"guide/basics/#working-with-the-project","title":"Working with the Project","text":"

To run executables in the context of the virtualenv you can use the run command. For instance if you want to use black you can add and run it like this:

rye add black\nrye sync\nrye run black\n

If you want to have the commands available directly you will need to activate the virtualenv like you do normally. To activate the virtualenv, use the standard methods:

UnixWindows
. .venv/bin/activate\n
.venv\\Scripts\\activate\n

To deactivate it again run deactivate:

deactivate\n
"},{"location":"guide/basics/#inspecting-the-project","title":"Inspecting the Project","text":"

The rye show command can print out information about the project's state. By just running rye show you can see which Python version is used, where the virtualenv is located and more. You can also invoke rye show --installed-deps to get a dump of all installed dependencies.

rye show\nrye show --installed-deps\n
"},{"location":"guide/config/","title":"Configuration","text":"

Most of Rye's configuration is contained within the pyproject.toml file. There is however also a bit of global configuration to influence how it works.

"},{"location":"guide/config/#changing-home-folder","title":"Changing Home Folder","text":"

By default Rye places all it's configuration in ~/.rye on Unix and %USERPROFILE%\\.rye on Windows. This behavior can be changed via the RYE_HOME environment variable. This is useful if you do not like the default location of where Rye places it's configuration or if you need to isolate it.

"},{"location":"guide/config/#home-folder-structure","title":"Home Folder Structure","text":"

The .rye home folder contains both user configuration as well as Rye managed state such as installed toolchains. The following files and folders are placed within the .rye folder. Note that not all are there always.

"},{"location":"guide/config/#configtoml","title":"config.toml","text":"

This is a configuration file that influences how Rye operates. Today very little configuration is available there. For the available config keys see Config File.

"},{"location":"guide/config/#self","title":"self","text":"

While Rye is written in Rust, it uses a lot of Python tools internally. These are maintained in an internal virtualenv stored in this location.

"},{"location":"guide/config/#py","title":"py","text":"

In this folder Rye stores the different toolchains. Normally those are folders containing downloaded Python distributions, but they can also be symlinks or special reference files.

"},{"location":"guide/config/#shims","title":"shims","text":"

This folder contains shim binaries. These binaries are for instance the python executable which automatically proxies to the current virtualenv or globally installed tools.

"},{"location":"guide/config/#config-file","title":"Config File","text":"

The config file config.toml in the .rye folder today only is used to manage defaults. This is a fully annotated config file:

[default]\n# This is the default value that is written into new pyproject.toml\n# files for the `project.requires-python` key\nrequires-python = \">= 3.8\"\n\n# This is the default toolchain that is used\ntoolchain = \"cpython@3.11.1\"\n\n# This is the default build system that is used\nbuild-system = \"hatchling\"\n\n# This is the default license that is used\nlicense = \"MIT\"\n\n# This sets the default author (overrides the defaults from git).  The\n# format here is \"Name <email>\".\nauthor = \"Full Name <email@address.invalid>\"\n\n# The dependency operator to use by default for dependencies.  The options are\n# '>=', '~=', and '=='.  The default currently is '>='.  This affects the behavior\n# of `rye add`.\ndependency-operator = \">=\"\n\n[proxy]\n# the proxy to use for HTTP (overridden by the http_proxy environment variable)\nhttp = \"http://127.0.0.1:4000\"\n# the proxy to use for HTTPS (overridden by the https_proxy environment variable)\nhttps = \"http://127.0.0.1:4000\"\n\n[behavior]\n# When set to true the `managed` flag is always assumed to be true.\nforce-rye-managed = false\n\n# Enables global shims when set to `true`.  This means that the installed\n# `python` shim will resolve to a Rye managed toolchain even outside of\n# virtual environments.\nglobal-python = false\n\n# a array of tables with optional sources.  Same format as in pyproject.toml\n[[sources]]\nname = \"default\"\nurl = \"http://pypi.org/simple/\"\n
"},{"location":"guide/config/#manipulating-config","title":"Manipulating Config","text":"

new in 0.9.0

The configuration can be read and modified with rye config. The keys are in dotted notation. --get reads a key, --set, --set-int, --set-bool, or --unset modify one.

rye config --set proxy.http=http://127.0.0.1:4000\nrye config --set-bool behavior.force-rye-managed=true\nrye config --get default.requires-python\n
"},{"location":"guide/config/#per-project-config","title":"Per Project Config","text":"

For the project specific pyproject.toml config see pyproject.toml.

"},{"location":"guide/deps/","title":"Dependencies","text":"

Dependencies are declared in pyproject.toml however adding them can be simplified with the rye add command. In the most simple invocation it adds a regular dependency, but it can be customized.

"},{"location":"guide/deps/#adding-basic-dependency","title":"Adding Basic Dependency","text":"

To add a regular dependency just invoke rye add with the name of the Python package:

rye add Flask\n

If you also want to define a version, use a PEP 508 requirement:

rye add \"Flask>=2.0\"\n

For extra/feature dependencies you can either use PEP 508 syntax or use --features:

rye add \"Flask[dotenv]\"\nrye add Flask --features=dotenv\n

These dependencies are stored in project.dependencies.

Note about pre-releases

By default add will not consider pre-releases. This means if you add a dependency that has .dev or similar in the version number you will not find a match. To consider them, add them with --pre:

rye add \"Flask==2.0.0rc2\" --pre\n
"},{"location":"guide/deps/#development-dependencies","title":"Development Dependencies","text":"

For dependencies that should only be installed during development pass --dev

rye add --dev black\n

These dependencies are stored in the non-standard tool.rye.dev-dependencies key.

To run tools added this way without enabling the virtualenv use rye run:

rye run black\n
"},{"location":"guide/deps/#git-local-dependencies","title":"Git / Local Dependencies","text":"

To add a local or git dependency, you can pass additional parameters like --path or --git:

rye add Flask --git=https://github.com/pallets/flask\nrye add My-Utility --path ./my-utility\n

Note that when adding such dependencies, it's necessary to also provide the name of the package. Additionally for git dependencies all kinds of extra parameters such as --tag, --rev or --branch are supported.

When working with local dependencies it's strongly encouraged to configure a workspace.

"},{"location":"guide/faq/","title":"FAQ","text":"

This section should cover some commonly asked questions. If you do not find an answer here, consider reaching out to the community.

"},{"location":"guide/faq/#windows-developer-mode","title":"Windows Developer Mode","text":"

Rye does not require symlinks but it works significantly better with them. On Windows support for symlinks is restricted to privileged accounts. The reason for this is that Symlinks were a late addition to Windows and some applications are not developed with them in mind which can cause misbehavior or in the worst case security issues in those applications. Symlinks support however is enabled when the \"developer mode\" is activated on modern Windows versions. Here is how you can enable it:

  1. Press Win+I to open the settings
  2. In the settings dialog click on \"Privacy & security\"
  3. In the \"Security\" section click on \"For developers\"
  4. Enable the toggle \"Developer Mode\"
  5. In the \"Use developer features\" dialog confirm by clicking \"Yes\".
What happens if I don't enable it?

Enabling symlinks is not strictly required as Rye automatically falls back to hardlinks and junction points. However not having symlinks enabled will ultimately result in a worse user experience for the following reasons:

  • Custom toolchain registration uses proxy files rather than actual symlinks which means that the executables in the .rye\\py path are non executable.
  • All shims will be installed as hardlinks. This can cause issues when upgrading Rye while Python is in use. These hardlinks will also continue to point to older Rye executables creating more hard drive usage.
  • Virtualenvs will be created with copies rather than symlinks.
  • Junction points are used where symlinks to directories are otherwise used. Some tools might accidentally not detect junction points which can cause deletion of virtualenvs to accidentally also delete or destroy the toolchain behind it.
"},{"location":"guide/faq/#missing-shared-libraries-on-linux","title":"Missing Shared Libraries on Linux","text":"

The Python builds that Rye uses require a Linux installation compatible to the Linux Standard Base Core Specification (LSB). Unfortunately not all Linux distributions are strictly adhering to that specification out of the box. In particularly the library libcrypt.so.1 is commonly not installed on certain Linux distributions but the _crypt standard library module depends on it. Depending on the Linux distributions you need to run different commands to resolve this:

  • archlinux: pacman -S libxcrypt-compat
  • CentOS/RedHat: dnf install libxcrypt-compat

There have also been reports of an error being generated at installation time despite libcrypt.so.1 being installed when a different ldd (eg: Homebrew) shadows the system one. In that case try the installation again after giving the default one higher priority in the `PATH:

export PATH=\"/usr/bin:$PATH\"\ncurl -sSf https://rye-up.com/get | bash\n
"},{"location":"guide/faq/#tkinter-support","title":"TKinter Support","text":"

TKinter uses TCL behind the scenes. Unfortunately this also means that some runtime support is required. This runtime support is provided by the portable Python builds, however the way TCL is initialized on macOS and Linux won't find these files in virtualenvs. Newer versions of Rye will automatically export the TCL_LIBRARY and TK_LIBRARY environment variables for you in a manner very similar to this:

import os\nimport sys\nos.environ[\"TCL_LIBRARY\"] = sys.base_prefix + \"/lib/tcl8.6\"\nos.environ[\"TK_LIBRARY\"] = sys.base_prefix + \"/lib/tk8.6\"\n
"},{"location":"guide/faq/#python-interactive-prompt-input-messed-up","title":"Python Interactive Prompt Input Messed Up","text":"

The Python builds that Rye uses are compiled against libedit rather than readline for licensing reasons. You might run into unicode issues on input as a result of this due to limitations in libedit. In some cases though you might also discover that the backspace key does not work or arrow keys don't work as expected. This can be because the terminfo database cannot be found.

For solutions to this issue, read the behavior quirks guide in the Standalone Python Builds documentation for solutions.

"},{"location":"guide/faq/#can-i-use-rye-alongside-other-python-installations","title":"Can I use Rye Alongside Other Python Installations?","text":"

Rye given it's experimental nature does not want to disrupt already existing Python workflows. As such using it alongside other Python installations is intentionally supported. Even if the Rye shims come first on the PATH, Rye will automatically resolve to a different Python installation on the search path when invoked in a folder that contains a non Rye managed project.

As such the answer is a clear yes!

"},{"location":"guide/faq/#wheels-appear-to-be-missing-files","title":"Wheels Appear to be Missing Files","text":"

You might be encountering missing files in wheels when running rye build and you are using hatchling. The reason for this is that rye build uses \"build\" behind the scenes to build wheels. There are two build modes and in some cases the wheel is first built from an sdist. So if your sdists does not include the necessary data files, the resulting wheel will also be incorrect.

This can be corrected by adding the files to the include in the hatch config for sdists. For instance the following lines added to pyproject.toml will add the data files in my_package and all the tests to the sdist from which the wheel is built:

[tool.hatch.build.targets.sdist]\ninclude = [\"src/my_package\", \"tests\"]\n
"},{"location":"guide/installation/","title":"Installation","text":"

Rye is built in Rust. It can either be manually compiled and installed or it can be installed from a binary distribution. It has support for Linux, macOS and Windows.

"},{"location":"guide/installation/#installing-rye","title":"Installing Rye","text":"

Rye is installed per-user and self manages itself. It will install itself into a folder in your home directory and mange itself there.

LinuxmacOSWindowsCompile Yourself

To install run you can curl a command which will install the right binary for your operating system and CPU architecture and install it:

curl -sSf https://rye-up.com/get | bash\n

Alternatively if you don't trust this approach, you can download the latest release binary. On first run it will install itself.

  • rye-x86_64-linux.gz for 64bit Intel computers
  • rye-aarch64-linux.gz for 64bit ARM computers
gunzip rye-x86_64-linux.gz\nchmod +x ./rye-x86_64-linux\n./rye-x86_64-linux\n

To install run you can curl a command which will install the right binary for your operating system and CPU architecture and install it:

curl -sSf https://rye-up.com/get | bash\n

Alternatively if you don't trust this approach, you can download the latest release binary. On first run it will install itself.

  • rye-aarch64-macos.gz for M1/M2 Macs
  • rye-x86_64-macos.gz for Intel Macs
gunzip rye-aarch64-macos.gz\nchmod +x ./rye-aarch64-macos\n./rye-aarch64-macos\n

To install Rye on windows download the latest release and run the binary. Upon first run it will install itself. Please note that it's strongly recommended to have \"Developer Mode\" activated when using Rye and before starting the installation. Learn more.

  • rye-x86_64-windows.exe for 64bit Intel Windows
  • rye-x86-windows.exe for 32bit Intel Windows

Note

Rye does not yet use signed binaries which means that you will need to allow the execution of the downloaded executable. If there is no obvious way to do so, click on \"More info\" on the error message that shows up and then on \"Run anyway\".

You need to have Rust and Cargo installed. If you don't have, you can use rustup to get them onto your machine.

Afterwards you can install Rye via cargo:

cargo install --git https://github.com/mitsuhiko/rye rye\n

Rye will automatically download suitable Python toolchains as needed. For more information about this read about toolchains. To install a specific version download a binary directly from GitHub.

"},{"location":"guide/installation/#customized-installation","title":"Customized Installation","text":"

On some platforms there is some limited support for customizing the installation experience.

LinuxmacOSWindows

The install script that is piped to bash can be customized with some environment variables:

RYE_VERSION

Defaults to latest. Can be set to an explicit version to install a specific one.

RYE_INSTALL_OPTION

Can optionally be set to \"--yes\" to skip all prompts.

RYE_TOOLCHAIN

Optionally this environment variable can be set to point to a Python interpreter that should be used as the internal interpreter. If not provided a suitable interpreter is automatically downloaded.

At present only CPython 3.9 to 3.11 are supported.

This for instance installs a specific version of Rye without asking questions:

curl -sSf https://rye-up.com/get | RYE_VERSION=\"0.4.0\" RYE_INSTALL_OPTION=\"--yes\" bash\n

The install script that is piped to bash can be customized with some environment variables:

RYE_VERSION

Defaults to latest. Can be set to an explicit version to install a specific one.

RYE_INSTALL_OPTION

Can optionally be set to \"--yes\" to skip all prompts.

RYE_TOOLCHAIN

Optionally this environment variable can be set to point to a Python interpreter that should be used as the internal interpreter. If not provided a suitable interpreter is automatically downloaded.

At present only CPython 3.9 to 3.11 are supported.

This for instance installs a specific version of Rye without asking questions:

curl -sSf https://rye-up.com/get | RYE_VERSION=\"0.4.0\" RYE_INSTALL_OPTION=\"--yes\" bash\n

The Windows installer has limited support for customizations via environment variables. To set these you need to run the installer from cmd.exe.

RYE_TOOLCHAIN

Optionally this environment variable can be set to point to a Python interpreter that should be used as the internal interpreter. If not provided a suitable interpreter is automatically downloaded.

At present only CPython 3.9 to 3.11 are supported.

This for instance installs Rye with a specific toolchain:

set RYE_TOOLCHAIN=%USERPROFILE%\\AppData\\Local\\Programs\\Python\\Python310\\python.exe\nrye-x86_64-windows.exe\n
"},{"location":"guide/installation/#add-shims-to-path","title":"Add Shims to Path","text":"

Once rye is installed you need to add the shims folder into your PATH. This folder is a folder that contains \"shims\" which are executables that Rye manages for you as well as the rye executable itself. For instance any Python installation managed by Rye will be available via a shim placed there.

On macOS or Linux you can accomplish this by adding it to your .bashrc, .zshrc or similar. This step is technically optional but required if you want to be able to just type python or rye into the shell to pick up the current virtualenv's Python interpreter.

BashZSHFishUnix ShellsWindows

Rye ships an env file which should be sourced to update PATH automatically.

echo 'source \"$HOME/.rye/env\"' >> ~/.bashrc\n

Rye ships an env file which should be sourced to update PATH automatically.

echo 'source \"$HOME/.rye/env\"' >> ~/.zshrc\n

Since fish does not support env files, you instead need to add the shims directly. This can be accomplished by running this command once:

set -Ua fish_user_paths \"$HOME/.rye/shims\"\n

Rye ships an env file which should be sourced to update PATH automatically.

echo '. \"$HOME/.rye/env\"' >> ~/.profile\n

To modify the Windows PATH environment variable

  1. Press Win+R, enter sysdm.cpl and hit Enter.
  2. In the \"System Properties\" dialog, click the \"Advanced\" tab.
  3. Click on \"Environment Variables\".
  4. In the top list, double click on the Path variable.
  5. In the \"Edit environment variable\" dialog click on \"New\".
  6. Enter %USERPROFILE%\\.rye\\shims and hit Enter.
  7. Click repeatedly on \"Move Up\" until the newly added item is at the top.
  8. Click on \"OK\" and close the dialog.

Note that you might need to restart your login session for this to take effect.

There is a quite a bit to shims and their behavior. Make sure to read up on shims to learn more.

"},{"location":"guide/installation/#shell-completion","title":"Shell Completion","text":"

Rye supports generating completion scripts for Bash, Zsh, Fish or Powershell. Here are some common locations for each shell:

BashZshFishPowershell
mkdir -p ~/.local/share/bash-completion/completions\nrye self completion > ~/.local/share/bash-completion/completions/rye.bash\n
# Make sure ~/.zfunc is added to fpath, before compinit.\nrye self completion -s zsh > ~/.zfunc/_rye\n

Oh-My-Zsh:

mkdir $ZSH_CUSTOM/plugins/rye\nrye self completion -s zsh > $ZSH_CUSTOM/plugins/rye/_rye\n

Then make sure rye plugin is enabled in ~/.zshrc

rye self completion -s fish > ~/.config/fish/completions/rye.fish\n
# Create a directory to store completion scripts\nmkdir $PROFILE\\..\\Completions\necho @'\nGet-ChildItem \"$PROFILE\\..\\Completions\\\" | ForEach-Object {\n    . $_.FullName\n}\n'@ | Out-File -Append -Encoding utf8 $PROFILE\n# Generate script\nSet-ExecutionPolicy Unrestricted -Scope CurrentUser\nrye self completion -s powershell | Out-File -Encoding utf8 $PROFILE\\..\\Completions\\rye_completion.ps1\n
"},{"location":"guide/installation/#updating-rye","title":"Updating Rye","text":"

To update rye to the latest version you can use rye itself:

rye self update\n
"},{"location":"guide/installation/#uninstalling","title":"Uninstalling","text":"

If you don't want to use Rye any more, you can ask it to uninstall it again:

rye self uninstall\n

Additionally you should delete the remaining .rye folder from your home directory and remove .rye/shims from the PATH again. Rye itself does not place any data in other locations. Note though that virtual environments created by rye will no longer function after Rye was uninstalled.

"},{"location":"guide/installation/#preventing-auto-installation","title":"Preventing Auto Installation","text":"

Rye when launched will normally perform an auto installation. This can be annoying in certain development situations. This can be prevented by exporting the RYE_NO_AUTO_INSTALL environment variable. It needs to be set to 1 to disable the feature.

LinuxmacOSWindows
export RYE_NO_AUTO_INSTALL=1\n
export RYE_NO_AUTO_INSTALL=1\n
set RYE_NO_AUTO_INSTALL=1\n
"},{"location":"guide/publish/","title":"Building and Publishing","text":"

Rye currently uses build to build the package and uses twine to publish it.

"},{"location":"guide/publish/#build","title":"Build","text":"

By default, rye will build the both sdist and wheel target in the dist directory.

rye build\n

You can use the --sdist or --wheel flag to build the specific target, or specify the output directory with --out.

rye build --wheel --out target\n

If you want to clean the build directory before building, run:

rye build --clean\n
"},{"location":"guide/publish/#publish","title":"Publish","text":"

Rye will publish the distribution files under the dist directory to PyPI by default.

rye publish\n

You might be asked to input your access token and some other info if needed.

No access token found, generate one at: https://pypi.org/manage/account/token/\nAccess token:\n

You can also specify the distribution files to be published:

rye publish dist/example-0.1.0.tar.gz\n
"},{"location":"guide/publish/#-repository","title":"--repository","text":"

Rye supports publishing the package to a different repository by using the --repository and --repository-url flags. For example, to publish to the test PyPI repository:

rye publish --repository testpypi --repository-url https://test.pypi.org/legacy/\n
"},{"location":"guide/publish/#-yes","title":"--yes","text":"

You can optionally set the --yes flag to skip the confirmation prompt. This can be useful for CI/CD pipelines.

rye publish --token <your_token> --yes\n

Rye will store your repository info in $HOME/.rye/credentials for future use.

"},{"location":"guide/pyproject/","title":"Python Project (pyproject.toml)","text":"

Rye tries to avoid a lot of proprietary configuration in the pyproject.toml file but a bit is necessary. Here are the most important keys that Rye expects:

"},{"location":"guide/pyproject/#projectdependencies","title":"project.dependencies","text":"

This key is used to manage dependencies. They work exactly like you expect from a regular pyproject.toml file and in fact Rye changes nothing about this. However Rye is capable of modifying these entries with the rye add and rye remove commands.

[project]\ndependencies = [\n\"mkdocs~=1.4.3\",\n\"mkdocs-material~=9.1.12\",\n\"pymdown-extensions~=9.11\",\n]\n
"},{"location":"guide/pyproject/#projectscripts","title":"project.scripts","text":"

This key specifies the scripts that are to be generated and installed into the virtual environment during sync. These scripts will invoke the configured entry point.

[project.scripts]\nmy-hello-script = 'hello:main'\n
This configuration will generate a script my-hello-script that will call the main function of the hello module.

Scripts can be installed using rye sync and run using rye run:

$ rye sync\n$ rye run my-hello-script\nHello from hello!\n
"},{"location":"guide/pyproject/#toolryedev-dependencies","title":"tool.rye.dev-dependencies","text":"

This works similar to project.dependencies but holds development only dependencies. These can be added here automatically via rye add --dev.

[tool.rye]\ndev-dependencies = [\"black~=23.3.0\"]\n

Dev dependencies are installed automatically unless --no-dev is passed to sync.

"},{"location":"guide/pyproject/#toolryeexcluded-dependencies","title":"tool.rye.excluded-dependencies","text":"

This is a special key that contains dependencies which are never installed, even if they are pulled in as indirect dependencies. These are added here automatically with rye add --excluded.

[tool.rye]\nexcluded-dependencies = [\"cffi\"]\n
"},{"location":"guide/pyproject/#toolryelock-with-sources","title":"tool.rye.lock-with-sources","text":"

new in 0.18.0

When this flag is enabled all lock and sync operations in the project or workspace operate as if --with-sources is passed. This means that all lock files contain the full source references. Note that this can create lock files that contain credentials if the sources have credentials included in the URL.

[tool.rye]\nlock-with-sources = true\n
"},{"location":"guide/pyproject/#toolryemanaged","title":"tool.rye.managed","text":"

new in 0.3.0

This key tells rye that this project is supposed to be managed by Rye. This key primarily affects some automatic creation of virtualenvs. For instance Rye will not try to initialize a virtualenv when using shims without this flag. It can be forced enabled in the global config.

[tool.rye]\nmanaged = true\n
"},{"location":"guide/pyproject/#toolryesources","title":"tool.rye.sources","text":"

This is an array of tables with sources that should be used for locating dependencies. This lets you use indexes other than PyPI. These sources can also be configured in the main config.toml config file with the same syntax.

[[tool.rye.sources]]\nname = \"default\"\nurl = \"http://pypi.org/simple/\"\n

For more information about configuring sources see Dependency Sources.

"},{"location":"guide/pyproject/#toolryescripts","title":"tool.rye.scripts","text":"

This key can be used to register custom scripts that are exposed via rye run. Each key is a script, and each value is the configuration for that script. Normally the value is an object with different keys with the most important key being cmd which holds the command to execute. However if only cmd is set, then the object is optional. cmd itself can either be set to a string or an array of arguments.

[tool.rye.scripts]\n# These three options are equivalent:\ndevserver = \"flask run --app ./hello.py --debug\"\ndevserver-alt = [\"flask\", \"run\", \"--app\", \"./hello.py\", \"--debug\"]\ndevserver-explicit = { cmd = \"flask run --app ./hello.py --debug\" }\n

The following keys are possible for a script:

"},{"location":"guide/pyproject/#cmd","title":"cmd","text":"

The command to execute. This is either a string or an array of arguments. In either case shell specific interpolation is unavailable. The command will invoke one of the tools in the virtualenv if it's available there.

[tool.rye.scripts]\ndevserver = { cmd = \"flask run --app ./hello.py --debug\" }\nhttp = { cmd = [\"python\", \"-mhttp.server\", \"8000\"] }\n
"},{"location":"guide/pyproject/#env","title":"env","text":"

This key can be used to provide environment variables with a script:

[tool.rye.scripts]\ndevserver = { cmd = \"flask run --debug\", env = { FLASK_APP = \"./hello.py\" } }\n
"},{"location":"guide/pyproject/#chain","title":"chain","text":"

This is a special key that can be set instead of cmd to make a command invoke multiple other commands. Each command will be executed one after another. If any of the commands fails the rest of the commands won't be executed and instead the chain fails.

[tool.rye.scripts]\nlint = { chain = [\"lint:black\", \"lint:flake8\" ] }\n\"lint:black\" = \"black --check src\"\n\"lint:flake8\" = \"flake8 src\"\n
"},{"location":"guide/pyproject/#call","title":"call","text":"

This is a special key that can be set instead of cmd to make a command invoke python functions or modules. The format is one of the three following formats:

  • <module_name>: equivalent to python -m <module_name>
  • <module_name>:<function_name>: runs <function_name> from <module_name> and exits with the return value
  • <module_name>:<function_name>(<args>): passes specific arguments to the function

Extra arguments provided on the command line are passed in sys.argv.

[tool.rye.scripts]\nserve = { call = \"http.server\" }\nhelp = { call = \"builtins:help\" }\nhello-world = { call = \"builtins:print('Hello World!')\" }\n
"},{"location":"guide/pyproject/#toolryeworkspace","title":"tool.rye.workspace","text":"

When a table with that key is stored, then a project is declared to be a workspace root. By default all Python projects discovered in sub folders will then become members of this workspace and share a virtualenv. Optionally the members key (an array) can be used to restrict these members. In that list globs can be used. The root project itself is always a member.

[tool.rye.workspace]\nmembers = [\"mylib-*\"]\n
"},{"location":"guide/rust/","title":"Rust Modules","text":"

Rye recommends using maturin to develop Rust Python extension modules. This process is largely automated and new projects can be created with rye init.

"},{"location":"guide/rust/#new-project","title":"New Project","text":"
rye init my-project --build-system maturin\ncd my-project\n

The following structure will be created:

.\n\u251c\u2500\u2500 .git\n\u251c\u2500\u2500 .gitignore\n\u251c\u2500\u2500 .python-version\n\u251c\u2500\u2500 README.md\n\u251c\u2500\u2500 pyproject.toml\n\u251c\u2500\u2500 Cargo.toml\n\u251c\u2500\u2500 python\n    \u2514\u2500\u2500 my_project\n        \u2514\u2500\u2500 __init__.py\n\u2514\u2500\u2500 src\n    \u2514\u2500\u2500 lib.rs\n
"},{"location":"guide/rust/#iterating","title":"Iterating","text":"

When you use maturin as a build system then rye sync will automatically build the rust extension module into your venv. Likewise rye build will use maturin to trigger a wheel build. For faster iteration it's recommended to use maturin directly.

If you want to use other maturin commands such as maturin develop you can install it as a global tool:

rye install maturin\n

Note that maturin develop requires pip to be installed into the virtualenv. Before you can use it you need to add it:

rye add --dev pip\nrye sync\n

Rye recommends mixed python/rust modules. In that case you can save some valuable iteration time by running maturin develop --skip-install:

maturin develop --skip-install\n
"},{"location":"guide/shims/","title":"Shims","text":"

After installation Rye places two shims on your PATH: python and python3. These shims have specific behavior that changes depending on if they are used within a Rye managed project or outside.

Inside a Rye managed project they resolve to the Python interpreter of the virtualenv. This means that even if you do not enable the virtualenv, you can just run python in a shell, and it will automatically operate in the right environment.

Outside a Rye managed project it typically resolves to your system Python, though you can also opt to have it resolve to a Rye managed Python installation for you. This is done so that it's not disruptive to your existing workflows which might depend on the System python installation.

"},{"location":"guide/shims/#global-shims","title":"Global Shims","text":"

new in 0.9.0

To enable global shims, you need to enable the global-python flag in the config.toml file:

rye config --set-bool behavior.global-python=true\n

Afterwards if you run python outside of a Rye managed project it will spawn a Python interpreter that is shipped with Rye. It will honor the closest .python-version file for you. Additionally you can also explicitly request a specific Python version by adding +VERSION after the python command. For instance this runs a script with Python 3.8:

python +3.8 my-script.py\n

Note

Selecting a specific Python version this way only works outside of Rye managed projects. Within Rye managed projects, the version needs to be explicitly selected via .python-version or with the requires-python key in pyproject.toml.

"},{"location":"guide/sources/","title":"Dependency Sources","text":"

new in 0.2.0

Normally Rye loads packages from PyPI only. However it is possible to instruct it to load packages from other indexes as well.

"},{"location":"guide/sources/#adding-a-source","title":"Adding a Source","text":"

An index can be added to a project or workspace (via pyproject.toml) or into the global config. Rye will always consult both files where the pyproject.toml file wins over the global config.

Each source needs to have a unique name. The default source is always called default and out of the box points to PyPI.

Global SourceProject Source

Add this to ~/.rye/config.toml:

[[sources]]\nname = \"company-internal\"\nurl = \"https://company.internal/simple/\"\n

Add this to pyproject.toml:

[[tool.rye.sources]]\nname = \"company-internal\"\nurl = \"https://company.internal/simple/\"\n

changed in 0.4.0

Sources in the global config are also considered for tool installations.

"},{"location":"guide/sources/#index-types","title":"Index Types","text":"

Rye supports different types of sources and also allows overriding the default PyPI index. If you give another source the name default, PyPI will no longer be used for resolution.

Regular IndexFind LinksDefault Index
[[sources]]\nname = \"company-internal\"\nurl = \"https://company.internal/simple/\"\ntype = \"index\"  # this is implied\n
[[sources]]\nname = \"company-internal\"\nurl = \"https://company.internal/\"\ntype = \"find-links\"\n
[[sources]]\nname = \"default\"\nurl = \"https://company.internal/simple/\"\n

Warning

Please take note that the default index cannot be of type find-links.

"},{"location":"guide/sources/#source-types","title":"Source Types","text":"

The two sources types (index vs find-links) are determined by the underlying pip infrastructure:

"},{"location":"guide/sources/#index","title":"index","text":"

This is a PEP 503 type index as provided by tools such as PyPI or devpi. It corresponds to the arguments --index-url or --extra-index-url in pip.

"},{"location":"guide/sources/#find-links","title":"find-links","text":"

This is a source that can be of a variety of types and has to point to a file path or hosted HTML page linking to packages. It corresponds to the --find-links argument. The format of the HTML page is somewhat underspecified but generally all HTML links pointing to .tar.gz or .whl files are considered.

"},{"location":"guide/sources/#index-authentication","title":"Index Authentication","text":"

HTTP basic auth is supported for index authentication. It can be supplied in two ways. username and password can be directly embedded in the config, or they can be supplied with environment variables.

Configured CredentialsEnvironment Variables
[[sources]]\nname = \"company-internal\"\nurl = \"https://company.internal/simple/\"\nusername = \"username\"\npassword = \"super secret\"\n
[[sources]]\nname = \"company-internal\"\nurl = \"https://${INDEX_USERNAME}:${INDEX_PASSWORD}@company.internal/simple/\"\n
"},{"location":"guide/sync/","title":"Syncing and Locking","text":"

Rye currently uses pip-tools to download and install dependencies. For this purpose it creates two \"lockfiles\" (called requirements.lock and requirements-dev.lock). These are not real lockfiles but they fulfill a similar purpose until a better solution has been implemented.

Whenever rye sync is called, it will update lockfiles as well as the virtualenv. If you only want to update the lockfiles, then rye lock can be used.

"},{"location":"guide/sync/#lock","title":"Lock","text":"

When locking, some options can be provided to change the locking behavior. These flags are also all available on rye sync.

"},{"location":"guide/sync/#-update-update-all","title":"--update / --update-all","text":"

Updates a specific or all requirements to the latest and greatest version. Without this flag a dependency will only be updated if necessary.

rye lock --update-all\n
"},{"location":"guide/sync/#-features-all-features","title":"--features / --all-features","text":"

Python packages can have extra dependencies. By default the local package that is installed will only be installed with the default features. If for instance you have an extra dependency this will only be installed if the feature is enabled.

rye add --optional=web flask\nrye lock --features=web\n

When working with workspaces, the package name needs to be prefixed with a slash:

rye lock --features=package-name/feature-name\n

The --features parameter can be passed multiple times and features can also be comma separated. To turn on all features, the --all-features parameter can be used.

rye lock --all-features\n
"},{"location":"guide/sync/#-pre","title":"--pre","text":"

By default updates and version resolution will not consider pre-releases of packages. If you do want to include those, pass --pre

rye lock Flask --pre\n
"},{"location":"guide/sync/#-with-sources","title":"--with-sources","text":"

new in 0.18.0

By default (unless the tool.rye.lock-with-sources config key is set to true in the pyproject.toml) lock files are not generated with source references. This means that if custom sources are used the lock file cannot be installed via pip unless also --find-links and other parameters are manually passed. This can be particularly useful when the lock file is used for docker image builds.

When this flag is passed then the lock file is generated with references to --index-url, --extra-index-url or --find-links.

rye lock --with-sources\n
"},{"location":"guide/sync/#sync","title":"Sync","text":"

Syncing takes the same parameters as lock and then some. Sync will usually first do what lock does and then use the lockfiles to update the virtualenv.

"},{"location":"guide/sync/#-no-lock","title":"--no-lock","text":"

To prevent the lock step from automatically running, pass --no-lock.

rye sync --no-lock\n
"},{"location":"guide/sync/#-no-dev","title":"--no-dev","text":"

Only sync based on the production lockfile (requirements.lock) instead of the development lockfile (requirements-dev.lock).

rye sync --no-dev\n
"},{"location":"guide/tools/","title":"Tools","text":"

Rye supports global tool installations. This for instance allows you to install tools like black or ruff globally.

"},{"location":"guide/tools/#installing-tools","title":"Installing Tools","text":"

Use the rye tools install (aliased to rye install) command to install a tool globally with a shim:

rye install ruff\n

Afterwards the tool is installed into ~/.rye/tools/ruff and the necessary shims are placed in ~/.rye/shims.

changed in 0.4.0

The install command now considers custom sources configured in the config.toml file. For more information see Dependency Sources.

"},{"location":"guide/tools/#extra-requirements","title":"Extra Requirements","text":"

Some tools do not declare all of their dependencies since they might be optional. In some cases these can be declared by passing extra features to the installer:

rye install black --features colorama\n

If dependencies are not at all specified, then they can be provided with --extra-requirement. This is particularly sometimes necessary if the tool uses pkg_resources (part of setuptools) but forgets to declare that dependency:

rye install gradio --extra-requirement setuptools\n
"},{"location":"guide/tools/#listing-tools","title":"Listing Tools","text":"

If you want to see which tools are installed, you can use rye tools list:

rye tools list\n
black\n  black\n  blackd\nruff\n  ruff\n

To also see which scripts those tools provide, also pass --include-scripts

rye tools list --include-scripts\n
"},{"location":"guide/tools/#uninstalling-tools","title":"Uninstalling Tools","text":"

To uninstall a tool again, use rye tools uninstall (aliased to rye uninstall):

rye uninstall black\n
"},{"location":"guide/toolchains/","title":"Toolchain Management","text":"

Rye is unique in that it does not use system Python installations. Instead it downloads and manages Python installations itself (called toolchains). Today there are three types of toolchains supported by Rye and they require some understanding:

  • Portable CPython: Rye will itself download portable builds of CPython for most of its needs. These are fetched from indygreg/python-build-standalone
  • Official PyPy Builds: PyPy is supported from the official release builds.
  • Custom Local Toolchains: locally installed Python interpreters can be registered with Rye. Afterwards, they can be used with any Rye managed project.
"},{"location":"guide/toolchains/#pinning-toolchains","title":"Pinning Toolchains","text":"

To make a project use a specific toolchain write the name of the toolchain into the .python-version file or use the pin command. For pinning cpython the cpython@ prefix can be omitted.

rye pin cpython@3.11.4\n

Pinning a downloadable version means that Rye will automatically fetch it when necessary. By default, toolchains are pinned to a precise version. This means that even if you write rye pin cpython@3.11, a very specific version of cpython is written into the .python-version file. With Rye 0.5.0 onwards it's possible to perform \"relaxed\" pins:

rye pin --relaxed cpython@3.11\n

This will then persist 3.11 in the .python-version file and Rye will use the latest available compatible version for the virtual environment.

changed in 0.5.0

Relaxed pinning with rye pin --relaxed was added.

"},{"location":"guide/toolchains/#non-native-architectures","title":"Non Native Architectures","text":"

new in 0.14.0

Support for fetching and pinning of non-native architectures was added.

By default, the pin is for the architecture of the running machine. This means that if you pin cpython@3.11 on a mac with aarch64 architecture, you will use a cpython interpreter of that CPU architecture. A different architecture can be selected by adding -{arch} to the python family name. So for instance to force a x86_64 version you need to pin like this:

rye pin cpython-x86_64@3.11\n

Note that such custom pins are not reflected in pyproject.toml but only .python-version.

"},{"location":"guide/toolchains/#listing-toolchains","title":"Listing Toolchains","text":"

To see which toolchains are installed, rye toolchain list prints a list:

rye toolchain list\n
cpython@3.11.1 (C:\\Users\\armin\\.rye\\py\\cpython@3.11.1\\install\\python.exe)\npypy@3.9.16 (C:\\Users\\armin\\.rye\\py\\pypy@3.9.16\\python.exe)\n

To see which toolchains can be installed, additionally pass the --include-downloadable:

rye toolchain list --include-downloadable\n
"},{"location":"guide/toolchains/#fetching-toolchains","title":"Fetching Toolchains","text":"

Generally Rye automatically downloads toolchains, but they can be explicitly fetched with rye toolchain fetch (also aliased to rye fetch):

rye toolchain fetch cpython@3.8.5\n

Toolchains are fetched from two sources:

  • Indygreg's Portable Python Builds for CPython
  • PyPy.org for PyPy
"},{"location":"guide/toolchains/#registering-toolchains","title":"Registering Toolchains","text":"

Additionally, it's possible to register an external toolchain with the rye toolchain register command.

rye toolchain register /path/to/python\n

The name of the toolchain is picked based on the interpreter. For instance linking a regular cpython installation will be called cpython@version, whereas linking pypy would show up as pypy@version. From Rye 0.5.0 onwards -dbg is appended to the name of the toolchain if it's a debug build. To override the name you can pass --name:

rye toolchain register --name=custom /path/to/python\n
"},{"location":"guide/toolchains/#removing-toolchains","title":"Removing Toolchains","text":"

To remove an already fetched toolchain run rye toolchain remove. Note that this also works for linked toolchains:

rye toolchain remove cpython@3.8.5\n

Warning

Removing an actively used toolchain will render the virtualenvs that refer to use broken.

"},{"location":"guide/toolchains/cpython/","title":"Portable CPython","text":"

Rye is capable (and prefers) to download its own Python distribution over what you might already have on your computer. For CPython, the indygreg/python-build-standalone builds from the PyOxidizer project are used.

The motivation for this is that it makes it easy to switch between Python versions, to have a common experience across different Rye users and to avoid odd bugs caused by changes in behavior.

Unfortunately Python itself does not release binaries (or the right types of binaries) for all operating systems which is why Rye leverages the portable Python builds from PyOxidizer.

Unlike many other Python versions you can install on your computer are non-portable which means that if you move them to a new location on your machine, or you copy it onto another computer (even with the same operating system) they will no longer run. This is undesirable for what Rye wants to do. For one we want the same experience for any of the Python developers, no matter which operating system they used. Secondly we want to enable self-contained Python builds later, which requires that the Python installation is portable.

To achieve this, the Python builds we use come with some changes that are different from a regular Python build.

"},{"location":"guide/toolchains/cpython/#limitations","title":"Limitations","text":"

The following changes to a regular Python versions you should be aware of:

  • libedit instead of readline: unfortunately readline is GPL2 licensed and this is a hazard for redistributions. As such, the portable Python builds link against the more freely licensed libedit instead.

  • dbm.gnu is unavailable. This is a rather uncommonly used module and the standard library provides alternatives.

Additionally due to how these builds are created, there are some other quirks you might run into related to terminal support or TKinter. Some of these issues are collected in the FAQ. Additionally the Python Standalone Builds have a Behavior Quirks page.

"},{"location":"guide/toolchains/cpython/#sources","title":"Sources","text":"

Portable CPython builds are downloaded from GitHub (indygreg/python-build-standalone/releases) and SHA256 hashes are generally validated. Some older versions might not have hashes available in which case the validation is skipped.

"},{"location":"guide/toolchains/cpython/#usage","title":"Usage","text":"

When you pin a Python version to cpython@major.minor.patch (or just major.minor.patch) then Rye will automatically download the right version for you whenever it is needed. If a custom toolchain has already been registered with that name and version, that this is used instead.

"},{"location":"guide/toolchains/pypy/","title":"PyPy","text":"

PyPy is supported as alternative Python distribution. Like the portable CPython builds it's downloaded automatically. The name for PyPy distributions is pypy.

"},{"location":"guide/toolchains/pypy/#limitations","title":"Limitations","text":"

PyPy has some limitations compared to regular Python builds when it comes to working with Rye. Most specifically PyPy uses some internal pypi dependencies and you might notice warnings show up when syching. PyPy also lags behind regular Python installations quite a bit these days so you likely need to target older Python packages.

"},{"location":"guide/toolchains/pypy/#sources","title":"Sources","text":"

PyPy builds are downloaded from downloads.python.org. These downloads are not verified today.

"},{"location":"guide/toolchains/pypy/#usage","title":"Usage","text":"

When you pin a Python version to pypy@major.minor.patch then Rye will automatically download the right version for you whenever it is needed. If a custom toolchain has already been registered with that name and version, that this is used instead. Note that the version refers to the PyPy CPython version.

That means for instance that PyPy 7.3.11 is identified as pypy@3.9.16 as this is the Python version it provides. As PyPy also lacks builds for some CPU architectures, not all platforms might provide the right PyPy versions.

"}]} \ No newline at end of file diff --git a/sitemap.xml b/sitemap.xml new file mode 100644 index 0000000000..0f8724efd9 --- /dev/null +++ b/sitemap.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/sitemap.xml.gz b/sitemap.xml.gz new file mode 100644 index 0000000000000000000000000000000000000000..72ac34fbaa67082e771e2119e1a8b8ac44503e59 GIT binary patch literal 127 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

I8KLq=fAX`(j>> zZt&s1Sl|6VgVhDtF?wgZ5XGP^H2Ovy*W~H~d0ZP{VCzE$D)-CDnctE38^YzBU{S0F zY@WXjKV&1JQWPs=>`6{xt747|Y78u<0`EssId=Svr>}ckf6YzpxUxJCYtF z1P+U|4cCk|B_Fw#XJWpDHUL1M3x{Bdg~FK!lO;^KazbB*TdLs2fT%2@5`PQcVp@l@Y=I<1jb*96m4QOb27U_!ZQg>B*{S7deU zfQHFgGQdk6HSa{(`2?+!PxeX*0%?ZNjuek{Eu+TQVPe(L?b3_~bnW-&;#v~(_@TH4 zq5W%dnH8nSh#jn|mx9{Dp);14){roiT$i82|ggRprhvsHFIZ$y-~6xXY3DYusJs>&y<%cje)>n@e!-I(h7JL zSN>aZ$;2-HP+Xu?$SopV$hlH?l98X`(bJ&=5OZeJQ9KVUoCKC+;eBqd4v&#ze}kL( z?W2(!x7T_#?{l`pb$U7jK&4yXH5IFM<%6*i8otP?&CrxV@e9JD7&sg{x>hDKp}-%D zi?90+#U)6$msD)ISeTcIYt(zVio3jKPsC-5WnwX7+yX$->9|1q;wq@opWxwD3Y(#o zJR=t!+3!xv&s*Cyc6se6?SLd@aTWtmcC?cyjpB`&5#lh(PqGyAo#FO9MS))`MK%%a ztgHk0Muk~EnQgf%vz_D=l=Afg7rjt2je#J?j_UB`44DAzBFRusC@2k&AtH5KMXcg# z+QR;+xZ-~*uKZA3I^T2ayQH=OB{0IN6w*$)iDaC))Rr=km4?Q}k|&u>6$52>!qmzV zFz>od!?RBpU5loeuE+riSRyQ5IvM>+ao$f4P+`;f7!fj#?eNj3R4gCGQf#-3q2rt4 z3M(!GgTEG6d?+q+S;$4-sa#g3i}W}*f`XncVpTz~X(Dc_8kEjex*M@w;X{7VKf&Vg zhf+vpDls2%AJ+Z zG60nr5lwj`X4nn3ZD}Zb}9f4RPGM1fH*Dx3*nY# zyrdB>ip)udI$w)%LYa1Sku%7!HS3uu?-s-_$L5t5AtUjXY3}O~WJ#nVrVyiRUK7Tl z;KvRNI64wxnRce8JCnZk;M48yV{yed#T7pkmxmnYZ^ad^by#bQT>5Ka=mZihQZmip z`3yP7jDZOq+E|xul+X9%+DUhPU-?MV(S*Om^8dq?$vDcWNh1BUria4p(elGu8(Q&8 z)Dq`X_$b-D4tr+-*_5+#hGuao97n~KzZ6&IpNorFD9Iv+S%eKDCN0Xg!il2IVl%mW zD>Zo{YPxd;A%u>qBLAntsw6|{&>ZhbHc)&A@vv|LrVH2jTWskq>o%}?)4Fc8vl0uX zfmcPPcOv*>q%+QQmvtT^&BO2SWO~`&1kp|y470wMXnwKLFKCC^YM=iC0&p=aXRW-t z%41DMjX#X|lWt!Sii78ow3F^LBB>Wn_x+!%`(tsfkROx5?c!<`S5I*TJ!is<%~x@W zW4EG8zi5(a0}}Fwe>arBilV1SCEX3XW{%8xy*S-TCuwQ zWSBsBI{auP(mQIm+)HMIf_*<*x=Q{yMEP1|sipVQafR%k*m@fy_!B3_!3L!aM@C6x z<}nWj{fV@+nTQL2k@Fy4odowr!LbQLUnU7331YD>GzIQ};jG=y`7DOsdu~u(YWe5l z+Q#))@clQ%6<2Yk6<4sh(k`XC>8OlW(%vInc(9}rn%sid)A&PjLL?f%VfYlYIo+7Y zcXVIM1V6-R!XLFblII#@*xD_qwb%+B!TWoULz|sR23ukBp zzR(5w|CFZO2+77E-8%&-y+98B-c1jDvC~Ko|5#i+a#>vc*W!w+xRQ$cbfMDH0L3l( z@vw}vcdX>-G!z_YBN$aj-DjVWGbAjJ{r;=v`kY(G#aqo24@&>55F?=GzE({@<31n9 zSk(q?Eow2NGzw#C3{NG3lWOIx8gbJx1_M1kh3J1MuKrVT)yLu@yONrtZDM6k$=Iq) z>dH_j(_%gmn~052Oy`u#|HnOua48MfytGu!Y%wTRNM`)*idPu(m614_#$Fw@$jJIK z&z04=&n{-JEbr|somARnHIg98LZXAL+N6~)?Es7bFJ_A;Mv&~v(aBw8-8B`f_$Bd) zrS9uasYhe^x)fsWRMO8gXp$VE2yKvK&^{%U8y7W2HD3harS5dkr{9a~I+ z#YI1k(?K6fV2`7Lii_r#1Ly#Ra5h-DYb(W-VhmALS=Q&B7NyW+hIwkWe}`u@E3$FU zcV=+{W5?6X|BS4cckV=d)7@cv3P|lIV;y(?rc|4RXrm>#i0s_vSgUN7nF8)}xv$CI z3;sAMOP~}l!jG=t+ULOwLg^3VH7?)4t+=DO``jB>c3vnXEBWjRk%0VY@QftWr%At+ zsD%3|GZ-FS{ct}1kHtlwInecYaUJ9CKNXk20Oxb&b#z%QfrWFl+)Ppu<6I-Y+-+oD zn6?Kn`&ttl82Mr=$?vNuH7YuK3$zY|k}4r1%d;jIueKG&Ev61U4;HTo=aI=_UwB~5xQvfTh3?#UMlt4_q2!EYun>w!+8nTMMbN@E4u#Q>F+_nEfNCES{BAMkuH z1=_)^JbYnPzEjQx+ddzl%~RBq+jeGcptN32i_}amr7czxXXd8*M5QOhe0`>fU*%+i zqqZTmm-*i;AIQ-Dm*T=}Q)J4|#dR*LjMdX@oy|guY4Lu*fsjs6 zC>SX!A-$sbixW2$I~Lt^1-f)DI7FnxvI{8|>s)Q$WUkDj5kp836AKFjK!|G+wFsEJ zqq{WP!FKg*_>vB9oDW*NkDqk1#&)hO*XJDsxp#5JtGLFc=PIt$W(!^vV!H4(Aa*n=A@+oBvbpNsD zJGU($6f}~0omgF@2q;Kzq+C3+l%DePFOYvJh2b^%L-TZxLExkGJp4kL=yS!azEf1yO|$52ZD&1Z80&r5^N# zWK0!Te_LD=4w;{di!#m+#Z|u)7pYf6pJ}qz6~fZW!U=KM6rM8oVa+VS-AY37LHD0A zQ)$##%CheHg4yXec7%$X)KPTQ8?U%plPOR z880R;6~~;r<0g$Tm7%$g9ht$IOCvaNr?|CD=sXu*E)h@4@NDtIsRS_l@(eRkEM3nv zEy!F(HPk=!L0zSFp&HwXIIx#~9{16?Y4rJ_xMCGoSaD5`a%$ZAxws~*WVtQ+Xoej~ z?BQCFR4yxQL4pnGFOQp8;AAnC>Ovc5K_Xx8G_z7S#DwUFC*5d8Z=}@QX!I$ zMFlx4^PZ)+0d7bSOW>6g z`8Nu}IT#VmxShyobFI9>KfUdu_M*+$-BbaQj&&gyhvqQemzw|I8iA{5!*6n7FrZ2q zTtlilzC5rug16F8Zdzd_$}gakcBcGFWbi`+F?t<-S6rEQaphfH&El&5rntzBoZ_kv z#T7KQiLK$x%bnJ)gK$PvUglT1SHdL%!9``rZX0K|oX3)Xb@!E0e+n^Mxqd6pSor6f zIhOcEbi+abq3Pk18l2??Hs5oUMKC#clml%c$}>R1U~$DNuCU^YkX6|5bpKdfxr-}T zam8`N9J~2qz%d8JCc6*j3$%H`p_3$%n1O4L_YPA<6G^OOoRK`)GrhxLLyRZeGx=iQ zoRe2}WVqvHzwF!tta{%~&*D(9Q}&1zl$ zx!F(baq0dfn=glHh~6r?4{wdW3#B*}d{lZ2P8m!cR#@K1P!og7qjp57k>!a7U~({# zE?~N{S8;_GSGvsHrZ_UXj5tvg74We-(yEMi}PL8wBr-8nCt)L@i00ErF@~Q9LQ!UISlP zgO)6={7Z4QygYs_t~mp*;>yv?=A_RWg%^R((_C;fION(ek~T*vdhX42*=T7}oO*~= z6d#V1XFSKLP+hEMbJ^Nh6Pb1hrDfE1)b?Lrh`Qx_sxz8KiYsCQRnvPw06^!IXZzq8 z35IgT9j|;WMaKlXX}M0qy~{H7;B}iN8YnSfr@;rnpRBUnTk5hqHgy18V8!Dh3FgK}CvG&qay6w9{?qEpg^jp&HKDy3mB{S)k-VMJ9tMch* zT*}Jiuz^||-be;pnh8jBnB~bi(R#{PGJwXF9&Je=R$O%#SJUeIYG`Cs z44H~6cX7qX;tCd5{7_u|skp2F;&OsE0u#BW42BWtUawBc{bg@AWNiiIC2mG(qHN@g ziK_lHwux(OxwbC3b98};!H)Ah7#)i4&DfWquM8=(O*&^&1lcQcji%W{8&3N=qgQdM zq1(l!01{A&?&8W%#pMED1;Ul>l(a@GvT(B%Y&@p5eDCezD_=FVHd{*HeZ)gGy-koz z)KFJmJfHM4Wg4#vcY6i5fb3^Wce6P$jNM{OJcGEg^z@_|h-H)NVP02JHiN}&j-ET` zcsw)-D+K$)9Bw|n^JoUmu%RdmP#(nr3Om9C=wo5MVjw-EzHBp(1+{>V;ujuGV#0a& zMN1pwO(1}%Lpotg+5j8pNTg!Cii<|6|B8P={?c*ovhaDvqO3n&; zpXKTolO0eirfdaG2{}fZ`DECAUtBT8#rOe853%RL8B8-IxkTlU#U&OZ8ym8=ED0W{ z)4Ag0j+Kgb#8uARbuHhfi4x^l0^IbUHXEokuDT0XWoTFKVp1G!d+`=ic`)fqtDULS z88)kupzM4hCQTIc(4F~c-!AvQsptdVLk!sN0jA0yg=CH;eA$5@jG|Kk%(64Em6Scs z_5cVfS?_Az%=zUG7mWm-xgOV^;EQg{;jy;e=Dv~ z9xk&Y#dH<(VuduumMHjsI=6*ZSrF#-B{UUfq#R%aaj&%a(60Wv49x|qOdDB-V3XQG zgTceNidr3GaO!-^{R=s}VV%tXJWh8odxe2-b*c>jr_-o3nC``lhE&-#|B($`ri5uUk znTK*%X#Y}Njp8cU30ZNGX86bAqF{>oYizXIytfq%nX$uyVmUvXO%C&JxMDPfY7^Sz z?GVFF1Jy+)SLCrJqii-oB$xqSh=LJ?yJ~AAW{+fq*`5nW**r`sr5DNb%@zPcT2+TL z&wP?%|rBtgZGGc1lV5 z1keZaJC1daqJGFYnGg>7kzKyN%06K5J&i{>n=#0@&GFIp<4!%jasd$@voq(?nuLyW zXOfY`w>S|OA2k5lpsnk$C3(`?K=c=gfjm8m5s)NTHe%eA+RdA=}zXVG07jqajo5NeV=y(q>kPr@Q>$i_6TPEp_55uK2dNXx!000`{Gp z?xu%iD)-%XIcmRb0OYN(;-;Y3q@}`A#6#6;QMvNbGnXQrUBTfkcO z(a#x65RD)5wytG$Fb- zaR6=1-3^XyESA=zS}#!Bne~H6msy64`{+5mn*I)O_LGB5I&hWww!^h3)bV&(K8jgN z5XwvRxHG%Ksu>4vCC65(qRO@hY8dzl*$_x&uKAYDq|mm}ayOn+=ygIPllW(dc_mZ4 za_x6`x*oR#LJKgO;aodF1p6(1U>*SsBKEwE#N{V5JyB#eii2B{a5nm>xZ+h@yt8u` z7e~f?hFxxWo0(v*;tH(98Ocah2Wuq542Q#gu;a=KVoDz#C_geTa0-XqS#{Aegxiz0 z+>lg~e2Az;9Inc{E%E#E6CfUZUPxZrm>o^n3ya^~87SGhg1oQH88G#3;B zR>WFlR=BQ%7(ORY6TVrXIow|lZ((GMB?liaMXutC*u`~BX@4lL^x{%d0f1BR5ko;X zZD+`#2w+W~;a8~|e6(D|W#(*EoJ0aRD~KxtK(=fm(>8lRun+m@b{^Q~TA^*YMzEss z5|SRaYi6vVg(AHGv$eSw(hM*1qID&OG2k&M?5ZJA%OU1tyI5(Nu%Is-I&ynNZ8I)m zcFyvwp47EFd5&HowZtAVrb{i9j!d$$xT$7WDq_HFv6YB3`1thl7&v%#^;u*mY#!Vz zKdg$qxDF7Mt50Lwl`1aS&#mGbM)UlU=obh^h>SQWi*h9tkZvFZyDS+ldw@_bw+h9* zl*|}LQfA(j;UO)e>b=n}71%8gv% zW|puEFPCH8l`Tq83F!E#xK6?|eh*wXlK1bcxZ*CZ$#q74R<4*Mtgzkg=b2D(thOHO z6@=D7_3UxJ%z-D1-x0-KQg1Y5DcDAZ=^cBlm^}q(N7$)48++>=l(j7liF2=C3} zeOxO(P}vW0u}^)*D7P7CBZAWj=I}GKmi?iJXH0Z3_Ko~N(yh_usi8TxwT3N}{P9W$vKiC6}JgFzW|nk)_A1HzTHd5TI#d=AezqvNhunc+Y7FT^J{) z02+Q@&6nrmw)KkC!v~q9%Ow}`G3~^a5u0%ZRRTpC2ZP+_S5nf)9-tS;QWjFhymb%e4`2q_jz5s4>z5kP%qVB*Tu8ANrbt zDLbx$O7cj5EG`)z^K|O^TwLwN6;@nv7ng$R7~MzoyA|Rz?JvErm5cTPq4%VoE1%4U zEc8C$4K#&JF?<6FB=&h3EA_F1wtdU0;y${VlWR_NBMX)_M(xmy0ZuC1Fe8`AoHJ8h zU+bwiVQm+RD?b(&k>Xczr4?5aOid4?!x_xsT*c)llDF}Ob&HT@*wO(_lffqby8>Q> zaHoJ?2jjGgE6a0$ugfge;`A#gxL=laX3~I^zM`oLP5cInl*x_-tqCz$fjV-RkJwWG zYeFMuH0YhQkZH)hsqL5+C509wMQe<(wF?9F1E;)FK71@I2@`#u!L-wNt6%k2$YchJ zwEQg;z-G5!r5NY1PbqV#0y(V^pYZ46V&eBzT>3RvaV3i@e=9C1TA5CFCd`&bN*)Wo zCya~6rHkWcj8<+q>g0!wL}i2~;&-{UIXt$}7E%=+3kzQe8oSvE7M5=U#r5!UtLUFE z3<$XAasms*{J~nMCOKgFV7e8L0^>dwSASbv{h_#A%l>n51+)sQU-2^Qb?1eJ9m3Tl zCa#>jM;TvRXf>9>2z|;>tEd|*1@;qO2K*;flX6y22i~9;B|(z9!;j7BVk_JwwofLn zuEqh{ZaL}bT3nIS&c2@aCFoE#5D7Ulb8eY9NM#1vI%_Y@jo4!M4uX!GdZBL=w2$Wi z*@KV~CgqYO%<3EDu#Nd*+8T8o4OiZT&Q~UOsb3SHi>v#k(s>t`2W_t6A`ks=m}3=} zj8|bO>bV?LJ+zXsgAbVt3YA*EoFeRUaNr3PRXQd&wh5Q1TPxE~p|xcR@L3`HmYM80 z?p3B8i?wU-u|p=FDt7=RHNap($Q<1PPnTwKd8NZM7uv;!>{VR-Z^e};E;pmXnv}r| zS?({Sv}I>Yg)cQVi?v#P+Y?=Y)|C9imNRn zfaP~Z>%EK1czoqFIk-a002A9^cS*=)U~elx8N);@tenHUyl9$amXsZVaRPm|S597N zGDnVCdRm8dU2Dn3?(29D7HNp|547BuSaFZ3l&wmzObFC3!6q@2Oi3yJskjW;dlgsi z;%crwuvZCf*|DWfCyjemIYJ#4XO=W5M04SuoQ-{3$nQ!qxs1LN`)r2e!2?pHn~ddj z#$=^*4;0hA2{LIk9f-={@saKwXFf^hE3hc7sjSa%&zugq%t&}+a!HbTJPCDp)k6-p zN5+GME`0B-qqhs^@5L2XShKTLam9DVH6**~6F`-M0nIXu2X})*&zqAPk(HMgQ&jqus=Z{g@URgPGd~<%R=sN;oDyeJl&J79*3u#G07;D3gj<=IhlHU9 zGgR^+_;YdD$}N8>u0TrUDlUXZ+4d`(#;y!4$GmYdOwK}=w8^0ia;q+jln--S$Kz`z zi($l0^24xw^rT#hKCuS9xY0|zqZ4fwubfYsm$t*IsPNK`+8nt7lQgXaX?Z~IyUj^u zl)6NgD`q51`V;pn*f1pdxaiDN7i}K`ZIlqPyZgfYHVl8E|Sv8J$ zV{A8(;)2d{NDRkQ-E$0SP>??smz?f)afKYgE%fJITyYf_e8<6VS(#znVrN>iwwEDg z4K9dqS2TkJ94(JDk4*d*3`Mi?YzOt1O>aBeAQy<@;Hki|in@-j@o?`wmzPX`izGh_ z!HlA&ensh4ZVm>iaw`~CH>KEJqZHZ2;xNzz3ZUku z%Y+eDi0xY%iWAnQzGe_!=;+FINwu+C%+gqGhG*R(nwYEq@E=!tfXs(QSsU1ndqZ!= zyd<27Fi}#F_Euo|OcPA<#3FlSM&(Bkjk@gjzly8#TCeoy;+oBN+u8LhF5L6_TKipG zOc@I0hNK%I3?pwUPL?w-1@;y&>fj=yxOB`6fjzH~vIU_H8_gI4b0#QJ(K;^-2shG| z1{B-4R?GJh7hcPihA>rQ6ic_tkvGPHQg?zpGBd%#|E{>=V{yeEnDe{hN-wVD4kh!t zkw#HHGaEI~?9tm0nK_Gzl1f-)J^gF~Qba)QNG0fDBU1{|8gvkK>_~37b@i-oUQYp* z8O_jzWM{$iizz(p@6)0sul*rx27I^yTvz>)fGDLHctg3L!txRZNlFnc zgSgs}Xt66|r(l}}cClTe=KvQz>IuogNsIUn?5=_<<(hfyjwMs1;ey2=(p$yVAB$^Z zAr3V9vAE)=;u1`vod}zb!LOrz>_^H_uSHGVJ`pP@!I=qRriBU=J9(9iCH|Xf7Z#l0{~omR86s2G|Lc z$aNptkx`@euVheFfB0)Ha-d0>NY*C23=b+K7w6HOdGc}Yly%*XzQYTHpd#IHmCQ$L zXa!IPwqv1)jto&0x%g>q5-fw3*k2hMY<;!X{;I2pG!Oo0<6pRzTj3}T+fZ`MXXG2O zv`eSnbBxH7#kg@Y{g}1!tGL*D)-T1i8kD=Z#;c)}ifsl}G{AF^OHQqqqq6<2mfuY+ zxQR-fQXXH;j!^kU;@MeNU3wEueA16CV~K$YaS4Iu#o(t__ugI5{Zy%^9Dk&e2)Qws zk^1yp!=FwjBEXvQF0Q(Yi>XxK6xRy;=8omp;u6|u_POcX>iM8KCnHDsX*Nl7L#P$I zdM!Zp_$Y#sj#_8?OT`W6z>9f{l%=M65CH^Aw(gIb?6zrVDKp(frD4;@K%p>&;|80f z7l(fBh#-2Vr6o6wdwCe7e@DXw@2p{vBo6hN+{ zUy&tcW~sH~G$x6y$uORWyFLoz;GBnZqT* zhGMl{ZRRLV1vEmP9Jpt?HAJC!02UxW@&CzNiPk08}M+_3LoykOl}?HrM>yq>ms zJd;#Bw8*g-8Wx9eg%_VgCWa(v771CFXX9H{ydW zQ$ElCYVavZU7NIUhi=qP1zP9IVxyLIUDHPlmA znlUMI`S7N-BGK~w?zh`kermZQ?_THOC1ivrozd=g^4JUM42`ZlfacI>Z+)wT#CbGk zS@i6iP0zOLZ0H@_hP#3(vuCJu!-SAO5bX@jt8CI$*N_)M1nrnth3%Vm_VQyH#P zQ{eN5;u@Div?*os48RTz@`ojx9P*ViLrL><-?+&gBH{z1PpJG6K_ioIxmb$K&WIn2 z5IOc==@)s}oYk?#hPXHQK55{|+$B2F4EcOkCV5K&;|9C7mQB7>&^Dt904lnINj@Cm(+L`)Xp2!iIgl>sopQb7Qcr zs6QQD^7(CxU~XKDzZ4f~D0gwiU0krm@ZxGhNdvoF{68Xh21hIm=Q8oD59fxQYe~am z(#dI7j$T;feXY(tbpqHDAlbyZAH^~k{BU%gr=q&o5OP43oRI*Bn+3kgKDx~DiMq`> zx+>SZy&nLSV=%w`U0l5^I=(HgVYd$W`9pEF!z~l!Fo*S=*quTp24_-Nf(g!3p9ghk z6ATCx3Y;;+Aoqm$00kfc`Ye)=+OJuBxQ;oxQ`d1_SR5s`U~_b(Zymygv`xZ(mv|b5YJP=0vB^%mxaxCp zY1bXv2+pIUnK9%N)eN0dREKiGgI)bhPvwXQL$!)xt#k5Fd0z~L9ctH#;LN?TuEz#@ z=lJ?=5r82;tz2t}l5(5(d@0Yzvg9#X_d7Xn(c)@M`P}v5axhz@yfsn7nEUISLR1L| z1srk=uX9=~Gpb$reWjJUMb`RZ+h&Z-i*MZqx4p-Jem?#IX!CT_mBz|%xG*%AEmmA< zEL4d;K|-|r6ARw>TwIE`XK|5-!S-g)_P(A!a!@@Q;YMUH?`@*p_4(}5Ci1{WiTv)_ z%u(@1RX5X4(rj1n)9V8l<3rPxOfif}A``*IBOV!_#B~qFv9-*il@uuFodQ{Vw_Go; z|5(xiBlzv&N-r*0nfEHLKyl@}xFWU6J4Q&|X1vAnQe22khoLXqJTYVwEX~jH0MI(%GpnSX_hRq_2VhTwM51pNk855MEqHL)fek_k9N&F2zYry0%+vs&#%O$IzqdZCiL5Mm}tReQ5h9ocBMtY+9rCL8dg>kCPFg|&y&Za7zG7vB0( zxwtzqZF_P9Ewy5=dx9uNe_qS;$~BdlW<^0MN(SNGo)7vSAb#npFlA>;OQabY}|D=^J4n;tL?W;Lvh* zYLLh-H><1bk+*Zvt$FO!6|-A3AcET4^bq?@bhDZI_Utkvd0yK!t1DUhHPaF&?iK%V zK2g}lZDCxP_$g@B*_AiD@t=yTKNnZ#t;_yYTxrE+GA^us%Jqv0o?)7rxTReRGDyV` z|F~d8ihXfm5aWh0l>r8ijK(6G85qjIqpY8ia`nLxDt5NZuuo>umDQxEW)qTXwR$um z^k`VlaCh5v9MUs2i4po|u0RLdVZoAVBY{E!Gb|f0w*ZXoAwGXtZ?%zlJ3R$;MK=Ol z&{qh{L1rgiM^}J^=#G#>+vx#Af@H2}cb@3a#YJ5j-J|~Z;)=Vt0+FTOvWWnp>HU~5 z&xJk?@)HYE3N#~nZazko09}U{H-hflHnHXID8v8a)~5OD=H$}l@Y;2BS@KwqD_%x5 z)eBFXkzBfh`xS%4O)4a$u+ATgTyv8-+hPpj1=5u0uHs4*SAH(8+QlUck1>$n#Z`B4 zZSToubD*SL1S8i(I0n;yPJdwhNtKtSbHdMfdWbq$$&rjVLnJ^_z$OH{Rf4kS{sA)i zw8ot;A3IuyxJ^HwpQc_(k+T(A=ec-qd$IS6P)acX^Ad9zahPaqtqkYYY@GFEuIdm9 z-CylgWJRc^0C!WjTKQ0mpQ9u!ntCngo-w5kPw+)=$$VyX;&AD)$id@C4UT;5=m4`9 z&bDkCE3Wvb;)+G&_Ts`ZKE;*AFd-PF=2{bQA{wdD@H9*#T>Id1&GX%NE!}-4qn#?R z%*25M((FH8r_%De`L647glg`TPC#CK7O;PuP|hd;ZFIq^2?qA4AsSiWJDX_j8Hx%C zAX8k$H|wMoFzr=b^02bvN;fk7Q*oJddYX9ImjzAj;1JuIeGvp4CCo}LVxbrV<6})( zpzWHQCqWfu0@H*M%2SnYGOUYc#@VIXT5Ut;PVO|=%i1oqH%lApmJsVP`Y>IRQ>m0L zCujKwj&H6bR+B!V)u4py?2_%p=_r;ONWN;L9q1u)uKP7sb!LcEzUFI)l>lV=K1Lh;)nzSe(qe zlEygXRD=V(U+$PJ+-_qJI%h!!U%J@D}OjvY$d3V zz7S@)4+P8>Y2jh1?wcsbZztC}OKS#1Efv*vA^D<2UTD~5Ji3D!0BvhZ$K9PKcW}-X z39e{znj(BxT$|TrzU*^l{6letZ_Rtz>zJZ3OSHKnl1XZ#i5oJPyiXw##ov?EW-4sX zrdM)#7*Jlhd4Y;u>d6pTSeMfM6X<>Brk!o#N)JpF zS|%g0>Afb)wI+dJf{;B5p%7siTuyg!AzYxg3ORZc>DyKZ<^BYd z@78AR7)HS5DaNxJF<5d}#xF$#cDQX6z@ti*PPr3M8g@9s_I00|>2j{5lo%X91}bHi z22D%U^iSHd_Sz4FczFQ0JIb9)vSarkI>jZ|EB0qX&t;gCLt*WZzXBtbdEcetSJvYy z)95K<>?Zvhntm|Y@Cr3c1ec|e{au$&}56c=sWJgg}^$h2uR z|1Pd!+6P$B;dyNmy~-Mo)Ja=Y!#G>E5!W#l?_P+96h}9#?g-ywT(mwiZws69z!wd1 zYh+DjoAJ;~I5-j+4Mu(|Vmv5UdXq!32y4PV?E*A=_NkS28+}p>KX>6%L)-9aZMw0resd~-!k-0tM<=wz9PdT`je?w`u z#mUSp-tL~?9&YN1!!b~6iphUDyC@FB0!YpueR5(B2}_|YG5503=hV2SS!ae$F7Z=^ z^fUIE`1s-odU3@!#no4FrAK34KC#DV9DLPegwl#sGII(gZD;RIm;C@?rZ9kk{N6?~viC zEedz_hFq%{T9l!<3fO!UZf6^S31pu#<$0t(9W?}hiUrZ0&t})

qJ8g+O7(NxO>V@lM|2%huL2Zpu`miN@H6_B9RsutfM>B$OKE+^`TJz~tz;A&19)bKbN@5ZiR8~)ps z44caW5j#QMx6vu=`pTXoP=Mh#i&7 zzjp+hNq81okA&pEv0!>e3o1hsPs9k=y}0uC#kDVD%bKNNl3iS(;tK8P^=Y>8X8F67 z+OF(n5XalT-_DKqiTTO(H32xRTe1<{{ zBw+-(VbIdjDV({$Jb8CB&2NBo7EHQUTw9M~&xjv+6SBD^&7#;bmcEOBtZ@va*bR^h ztzNUmT0UZwZV9}kQwzO6;gdje&x}wOK+KNSTrCGt(`oWk)7Z`5fXkL?u^FJkseUM{ z&HA<>1Y$=v4LoNeL4SE8YDj@`!3A^ZIOfN=_A^M|uyO23Zf#0@dR?5=Pkt?~1$_xm z8=`pbQCy+N16SA;M%AA8#&cQ7mo`p6FWxV>n|#C}T1HQL4`3iQ+#zNF8r#d z^zVYNJo~tyc@aj&k}Jv_3rYX(N*>AOC|M_uWcpGfS#iZ%ab*LF|E;*vi>t5VVnCG_ zSDTFAz-zv_cFbLA@jDFGh@Ci4sZ2t?ax3s(g3KjE0c*UB1jQ#>V9w;SXcYXL3>)OM zW$Z4b*-%wXTAytIzoXkThaqor;a4rpQVK{&k(?Fdj(d*UcF9PU!Qq)m+kVORX}!xJ z)k4AnVOfdDf&Y3ah%1C?W{c0GK%ZfvhTeg) z>bO2KZEp_pl4q6MOb?s2m1%880g7x9^&^k2rOGHmMcey=&3;Wr=Hw0CPQo)b<$K}p zPwq|w&`g40=$6<0$cNtXMghzvOw*!VWHRIn!U^kLrRYDxKI;l%79UoIZCKcVhbq{^-^CA9y2|@r`SEEf6=x#f!&I`NQF??$<^Zo;YE?#sYhq#O0zoSpEQ&( zet@G&6?Yc0Hso&&YV&O2Dj3Js(qXUR-Tzl{MgCA+@I0D(I4wRNy}(&POq^-b;;VtY z@yR%UI3Rv~3;OFjIjBLuIPLA{g_Y7s%!|qcGqJ&$mwIt!SACP4o!XB`tXu%;So3qs zkcqYW)DBqJABT9W5Sai!&) zh&V!ClpuPa@l~?dbJ>9ylu*en`222o?!gmV$A{pkuw6I5Q28r89RYE)vT0(~lq1x+ zU3u#@jvQ3UT%6ifss+LT4BAJNCv?5;%akw>_wyn@+Hs2GpLMG zHrt|T`SrulT0rraLIP7J07Ag#E?2?a=a9B3mvIbwzamPD(Pyvvz6U=SP>)h7cS1rMU7cF8ihbs<>jUS6b15j3>z6 zYO}OKYSASS2Tq`vO?nPmEN1cDH+K=prKEl9gS;uSX4Ox@p;|j^Sm>j)`BB?Rbg}h# zYdPc73MI(PH{tQ`TZ!6_L;#F_jI5LbjDg&iDxUL<^^TU%DT7MSHN0Qq`;>tkX-bP} zaRHi_LQWJ~IT%Cu*CG@qlnO4q<<`W{aJA{b^GqpQVuUOr#3Xb)iwmOC@5PnO@>5#R zx8m}cHtit8a^|r8w-oDj4NEBAaE~V(e|K7&u*HJJ70<=DydX=<5i8reR@c>sn6h2a zhz%}t*1m2zQ`v7VSY?lp2+qGR|jnVTs1pBSH(uhMbf)^E6?mqlk zTuua2ab;TI0+g#VH<4o5V4~SNrQy>N&taa-Z1QwXnmR)S8;sz$f%o7XU2*QYz2iNZ zH>~C!jEtFNG|q3k4litw zv_OjTHPS?Pb0RS~u{E79Ez5ayebho7>*&(C*&*pz+?H(|UDG<_aez2gZP&KGrzqq6 z2;ofI(eLZv`h9W5KP#?yW3_C>_{u1C%0V7}2qh(8HY~Wu3|J+j+W%Q`8z&xr(z5{% z_DoV=S6j+R@8aMhmfX)cpeD4;;7zsB@EodOJ$jIxJ0dOLZ-JK*F zXHH-enyHf|T1%6u=CXIMwWgr$v9!xfRadkVZ{Mn-{l)Rg+T!E#9q?kCpyITQ>LG2+LwV>N4iWCGR&bP*nD4Y66lA zUu4C_R1Evr=J~+Y`d=!pe0?oKsle22FFST7_qIl(&hRm#I+TMqVi=1_O2MTxK_>^U zJa7#*G;7BiqNPJQqCMec&A4NU(sdm>-4El`AAK-0+no4bG`r2xsZ0a1(mk>2CS>Ys{Bk-e+9igX_om#jOxxOjG@LyMdq<)LJ`g^BCRSV1!S&?^=*B4nnu zN4L$eLws6q&dv@F(peOkcC`$vUx>~|m3a#684;|pXNMEa50r>VCXeGzf=hL$dKjFo zTI+jpm3h{$hUl+~>+;)Q#ibEF|CTnw!pLol89xK-D3|w!VBVb`504JPM?xedx%u>9 zQW13429b|Bw<5E)a*qi)lOtey^oaEgr>N?mcY)D`_f^|-XCa;?OreIQ*|huOAWyYj z0i%148)!Pb8VYpSq^k|o?!k)=x{6J2hFFR|7G9LoqoP_qW9#UShZttlW7}Bv|EuDXmn6RxSK3X{*L(SrHSKU?GDXH!Ne;L53hqvK@*rT+ zJ+ey{W!}UbsJ!Mpot>r`B=a?D+hO>%$VqZ9QyAEco-jtc)A?_( zQO_*7+ioD-;5E8ZNmyKj5Tq7Ok5iD3c%1f~CKT$}l=uZn}sUjZu>B^zSmTK@z17>H3!3p}-^w>!SBOz|<%p)}mg68LrFLxyv zkcI@b7qc@g?Ai%aTMA<+kz`aHVc)^v^8D=%LS zT1+@ewR>{~vR&#p-}zx^jn(ecb)V%9&s;M8CeFM7JbdA#<}-%KGO`s=D-gJZSU5z> zE;TRrI7#GMNG0A`0uz(}uDC`xDy;xgc$_d}u-&npw3u%-r+g&~`;hfW_n z`t|X%fkY=$ayr7h)7Il88fPvkJye6^+gtjHXTW6gl6Xn>+?mm4-K#BtTBXI-MrL54CqUiS zJDF+3SoFoU4RL1WS%KzNT=C1|LdAG-UD&*tgi-yJYuZl~Zt`(O}M&~E$a4PpjAfW%}@$$Ev9b#&Q0sV4CIqRZTiUj;R< z;IfndAx6F~?x5f)Mez`wtW=oylQO^rcBwR_d)ik&d$9SZRxYQd6La~{Y`Hq1NgAke-?kX<3=l-g=!ir1$8=DmS_HBJSsR(W3%+#AH z(d_fM@>Q54&_3yYd^di-0raRtPA5oz=G5|87g~gEdE6Aj7ZyEfN$GP~m2$zu+pcYIJR`yJ zh>6I!j|P6Zxn@YyB7+n}V16@s5E|y1dd1pFIj|@9VP3i^U{vrb)hysg^X0B`gIxFO z{B!)S{!+BiWxmCQTG7zLVnpN=I|9l1Wr8ZSWolb)gapVWFTo=k)wR{aI@XFSSzHMq z>{VPj#U=gLRa}`nYDVE&`x5q8F0weOd^fjjnC;I(o^wwrL+dqp{xATYTVRtLjIj~P zsw2IfRXYy0ui>#f#KT0%v2NLOF3R|8f}4D#iblpt6b*;XLQ!7y zjd-1xptyX#j?)RLJBw2|A%jIN6RL}o-&7zgVl3#7BoD~=x9Ks1P-xtF(cuXQ6#4;w z5FVf!SLCh6^XD6ckH5!EQ`xa?5_jylkz5u%BcqM~Hl1@z9SykoptTTsp?f5v#?ICh zO9WrK#h!WX2yOfa@rXH^q~l&R_r~o1W`Lku7<{& zi;3lM7iYStC8{6W8F%9 z?wa6Xj$9ytf*qlrMti3{J8s_RxGUdqUJ!h4b)bA;>yh(lfc;HCZR2{YaDxJ4`yxzU z^Dh=xSa8;4DgRttTu6@$1Lv#WjFZ?qM(7CYkc;UYsVjt?U72#6Y9nV5J*C*LF33Mv zv%n@}k&rbDn{2K>rXyVWkgj6ypnIEl#_WjRFw~OWpmyN6+B1l^Bzh|>|9Laa#eFHT zJ3iUWgHUQl*D9tl`@Q$-F!xsEQ;WbQfTcBPsA^fIsrWKZT+K-kkOf|6dhc%jGF=Au z;yZnN?a!CZqmgs{Lvig2Nh5VXipvhn^$wb?9Tsw8_AR!1VEu>J&^-nfr8t(R*)p!S zgxO?#ryFg7C?V5nE(aIt5?JVUV|-q4k%vfHs6q*lr#?MR%F?sWE)KEIuEe5eJP=mJ zRevfjArXP;`Ck;5303P>cJTCS4&(}49cZxunrt(8Ox!Q1T~Lpdhjy*gVB}CeaN6xZ zPWc&;Ogyo5r~Q_zGO;6IWTU>6Z0`b;@Cp@F0 z=F*hy#!MJExR4rV)_b?Nz1W>4P`J788rkk>L21Yz+GbHLEkuz{- zaKgl@*y;1){Znzl#JP*B>_og))8@XN;tDISard^F3ps2EswgF2rh^q%Q#IOH45lJ* zwsAsN0Fc53TUeb%vXSo1UD4APMNQA=oL+5cJQB6`bP(nXvr9Jy) zq>1kndpo*#SA^#McC{_H*&b|ks&8po!C;wdc+rMjgn=Y&YABuz9- zMISQ1jzKvYKx*=cbVRJ}f;-L4lqCMbS#1$qw)fzBi}0>+GkZ+*0Qm9^c$wwLWq)xt zg4}uE7g;6Qar5*k-!-@x#NV2LqU18JeHr;}u^g36UDj!LVIy5poSLvG2>33pSjCk; z6&HGv6@W0H1)M`iWYa!;&JKm+-7$(GcNbw9sn=7l_i7jdIXC^5D<#A481{p2>(UY4 z%_zpI6U{opt~$#eI~_I}^-FYZIeKeK%k9sZIQQEXi@C`op%mv7C37O`^S>-EN&R1o zOHt`wT=8C9i{q^|xI(%HPc}}I;+u^Db^7JQz=YG^ZEf?2F^?oUE=}b<>%H^1X?G_q zfCaR5g?E&AR{IbO9K!y$7SBSfGD}q z&cT;zN7HT`zbh^V`B`zrdvU?70`0^Zmc5fKsC0TA169(5|5A8EfRns=(0e6A1L7bu zrD72*r!DUUpgG71m?|Q*uO-K|(8xB8&dRhN2%jYzr6b505~U;!E%Paa^|MWlv?y5x zjJGL&4P$R<+H-hdQle;0px`)}qcpPC^(9Lo;WfjllIYdN2Jx7t;2aD2*l9B%NgdXy zBV*EwQBbK_rdZq}#Zgqtsq;%VqSw-T_F(M$ODhvW8U9>c@x8d9Ui_)J(u*rpTtQ9st&6!s)!&qFV3moN%^cg3uk7|Jj(FOWa()@8X&OH1uSgzmSLhrMNodH^mjJ zxMoGOgd91CtL$ICvUd)YOlFjfjV4~MLq{Upr`EmZ1in?XP3d^a?7o=cDVzYO0pV)4 zGY1VRZV_YmsTF>)mY~x}$k|KIAVi`CSXx8`3tG;wth2Dh0C&I}i*IX~`c;(5E)Kb; zb2lL$gXIpseyQsUp{d4?x5xWRXcmssv1joV%66!_vK6^l;rG8Eiz~hq7eZQ>UHG-Q z(q^EPAGPFXOi}h+AL*!49IF*M9iEy>^L8V!y{%h2D;GkMFwtF8cdDq|5>B%|x<^VQ zKBCRGpwpM5>q{bIx@N97{#^kSVX8$QR%v1G6f({(UBxv=SJ1rp$KuNPhs70ET&dy; z^_e>OR$BYE6d;w&9F*aMT7p&?+@yFb8>`2ZAzL0UaTd1*@w>P-dc^ZGWMn{&L(kUO zOel~rT|?k`U*V#Cr8)IJy>vRA&SEKRbP{=2ex*{U4}$vc&iluIW%Rn@BE~BXBFWoY zF+|XC%|#vIeE!35vMVE}O zXV=oBVGi>QZJf1xWZUNq3E3f2zF3&h3nPpiuN3wWb78CB71sbF@j#`6(DUCZE=fE? zkcIs)+O-MaDDUuMReD6*#Oip&8B%Li&4?Dy&^u?Pxz5!(A-2e?_(!6xpLn{`&gJCV z8Yy%?ihE0kqvH1}*XyN5`a5nw2wu5vO&J=G@s~$`_np8R{UDn6jg#Q)FLdoU)y*&m zu$~e;oyxOJ+^vb>!*8~@WBEKwx6bKUwR(1ClZQD}tt1vjo#`&FCB9N|wYuh);_9D@ zE5mtO82`-^WFH1XVb6$lmMyf$ zsPC%i`}J(`K!?tQX`mui!{Vng(PnOV5D74rq@;$agbFrOSPR*q-^btA1uT*yHk)%aRm#yNj9sy`PO=upq%%1n=9PD67gLyMsgAwAvlsV%JR>{Bo!#GiuK zpX+OrR)M@4Y3wN4DF-w3nf`{iVm3b>nQbnBb#dfn*;MQaGsi6IA&{S*8S?2p}!j11dPGw~AF5A+feeY;cH4B!3z{E}EO%8#z0q2mW62fac; zf8&njHk;X$^Q{|&MF`(_f(5o8g{B@ny&NdxL_H}l)rzZsTU@E)T8^*mjz1L_`Kv+q z83{8;wVW?qUll0_9EArzJ1n*5F}<-d7Lo3XQ2WG2gHu^y`F-bfDJct!p0Ret`hnl) z7cY=scw^0JedGC@G+hvk_G3$z_PLvmf8?j)%D*bE{8MqoPsIhHR7f4QGIA0tt(VjB z0_XGv$hUAS!IJImA0i_*mi8pljGS%*2t@i~<~NnM2W$TUI71J}e-1u;v&zid2Po%c z7WY|p;=NdD$!7v$H$V?pD4(+66;+^nk51Ae`3FvyKr}{GJm{@27sm|G;Y9i_qM8xD zlB*?@EHo_Hj7h1}way@yfxDe=A#AhLrW0CJQ2amIMZGAl{&R8Vqqy?DxN;R2M&{aT zCJh)`ft3&z=mG|YMD7+&KZ76ef752nh{3j>f!ida-YiGHWh)I(tB*6U=5w60c~rI| zq_GsDR2Jku!Gg*|N}lH}z3;d#IcyiaWL!zNW^u(`T%qD3 z98q7$0pvM1dTzS;Z0wYd7uzAjH>gQ<{a!V(Rh&Hy+m`o6S&mOaFD8dWFC%AJ*Okzs zBg4-w8Zj9`XGs)C%!8nBs0CB6czJ z?~F5wiZ5;CRM&`~Dt+-p)>+|UoGz8Rx7hh%6j47MFI;PX-V_KXu$9e(L)Op5#e2JW zq`xb!ekm?nm={K1whVW`piv?v<@BssiX5C>@3^M_yeF0Hwls=%gH4mUfawv0&SCig zMt3-)3DLW;gEex=*01DRi;7P8@yZ@V{a?1ub&fu6P-f}||GCHP@%!SMe2tOvOjTGo z-9IRa!n6mTubGGCxZSnDo?mmz+gZ9H`Qx&HDP1{g1j3jcOUDSx%OEN7mLbER{ zzWOn%$EmpNFKGrkcnjQk)TyIul01~HWrXKlT{UXoPCkaf(=a3;Jv9{lJlev~OxE?A zuqanbmh`>2V8R{C=#RyfUR?B##yV}T;*vgA2h|CEyexqeaA>BO&+&`pxMvkjgI9BH z1%9XA99fnaod#63*deOE zD&IIY*nWRiTw%pE{su3u@Z!q9FD^137{fQ3?a$$Geq?qxg5TfLTVBi}AJG;}Z|~$w zJv4N{*##-3`IRDF={45+B#w$uvsf2d1>ETbr;&1yDvpxGHPE(;CS}txmCER z%JuRwv9D<7?kN_@D%?+sms;)xNz0Wd$s7FdX->PN31Hf??iOMIkM72?N{tZrM)hqh zB`)1|k)^{tJGIlZ9Y=!X|NmHAS*y69c}*MuDGG62dEluTM=H7gjF^-zNU;tOHR&7= zTbHI;St+9!yianv4mowUlN&Q^Q(IBBBpvxp+@*L(D2PkL3+>i&;k-hIlMrfg74b~z z6YB#-d0Q&IU9-KoA|ccHvAE)IimN%tAv?@`AD{AS?!;7JpP#>|)W!8Z%=x=U?Y5o` z<`8oufLiFmI};{C5ou{iEXE0a0E?a7>mi?2hIWHc0?+8y^;F0uTKrCEU0nH>#T7pn7lNKrw;0=BOYfS=sAk>B*0JQeXU}ntxDtsW068a# z*gUsbZLVyV%A(lzp{xdDcQ#AQ`Oz}ap22^~C=#5Y$`4}vrLoSz1eE^%!c`)e?2w-D z?PdzeK{DjP7qTr#1}czq4i2SdHhU~ZVsWVm`vw@#v#=b{HB7c+rkU}hEx~xbSZ@*f zOz{P!MU_vACX+)DuL#1=*W!vtah*?R7Z+w#muS~*MVs)a^GF#ui;ANQmo}0U`dhi> z^r?+*tf$`)ym{s3KD>eU5R~m8x!X&cGeN!keAw79yr5iPxzqjjvT7*#nmb@LhXNsuhWg#d%fEYRzf_0-6x;bm3X3S8)K7t z{WRRvBOsg{A{JL4m^>~P?ZdI8VItp(s}B+27sb^-7nePeA+Zr+wD4K8Q5n;~KDv_g zF6mb27Jh{1gv%tCGSBTp2Tx7k_E|Fx?IvO;7A!;xcGxFC`w^~$Gi@zuW+$WTg%|K9k!?eQWkezq0l(22tz6@^aFd$$Z*o37PH}@ znX#`WG~EJ|jh`X*(Pe>Brl6SDm`*Uj^|&uSe?UVf5`fs)yZLc+5kh)C%h@;A_v+#} zq-Qk7Q0_vcD~c;+*b7C-oHZ~uO_P#jVzi|2dH#Z57FRusE7srqy|`q+!Q&SgcBRef zadef*=C$z7)+qI6tZvU1HHa8t*qd2}wOBGom>U#kq{uTo?&bA3ujrw^yj&P}dZgO= z(IU>_a>j~9EJmw_olei}+q40@Ay}=rVu~xS;>v$eTzwZ8Goe*n{U|Ps?by^GVDxEi zW)(ovC%27wz4HVyCWw1wVVg{GWw!tXJ&W3lK|lp9Oh%!R2o?jB$=aBO*lZTT&dbH% z?R|Fb!fJcHLy*x1t>Yus=0t?xGR5Dv3Sy33I+oPTw|4K%$b0{zoYJUvN4IR@f>5Fh zJo+2fyC{fyyj-bkaUEIL_&f}Hxx;z}rjS8>J9 z#YKlKKJBnDS-&w-4!^GWx;ieaEVdyDBB3l6%M^dPCOor-%pPSG1$Vf9?-V5<(M;mW z&6nHZGqW512;A~2H1AaP8W~+~69e@pP}^`)&wt&DtG&1cXjD>p@FC;VS}t5`rAEemcG<$Q(o8`qu>-=Aw`8er za)n7+9?Q6yZzOzNIi(anVrKX$n9|X^E{y2CI1(G>0#m|jPD*s+kdkV64<9TwX44Ea zv@Q)^QlY^tiz|OqT;L;~qW^PoSug%9E_!GkV-aPVbi?d=(#C{QzzON8%QmyKJItN^ zNXVo$Z?)@n2XibF90wc~tw!;caAORg^LdrL1O4#Xor$S15?> z7sVASF4)Sy7gzij#bv1w0`o)OVOS3;aAqFL1l8m`FBcwCgJTC#c(yt^phc+fs5O^Y z_8;FHBN(+5m^lIwXF)AuBH)c;#%Uy%cE}OmwDa1(*t)KZV13OI?!4w#(sl%D}N@Gf8`9;{t1*25KO6MJ>%Gl9@{-l(7v0vCBQnNXP z*Qj$D?iXrHc7iX^!s-OSlz=%3FZ%Jd181a*5!8M26H3){_+I0qZc8mcW%@BE!M3pV z{Rlywm?yl+3t~;-lEch}EUtN|p_O8BVJSw#bBHc@6<5F`Z=E=WCnDjSXhM1j-89M! z%$C=@P85#Sdbt3T`I`L{-kE8`(KRLC=Q~xBM;F8_&z{RYjAO0*?0d1S9{N$1z1~j5 zaVb<|rc319A$>%`@l{+s{E0a#y|4g-DGx{;uAM@jTZ<|d*W?!DgHXbw%ck88q~?D< cp#KwK0L*$^duJ&O8UO$Q07*qoM6N<$g5OX?T>t<8 literal 0 HcmV?d00001 diff --git a/static/extra.css b/static/extra.css new file mode 100644 index 0000000000..ed9751a21a --- /dev/null +++ b/static/extra.css @@ -0,0 +1,104 @@ +[data-md-color-scheme="default"], +:root { + --md-primary-fg-color: #7C9F35; + --md-primary-fg-color--light: #ADC541; + --md-primary-fg-color--dark: #9BB029; + --md-accent-fg-color: #54780d; +} + +[data-md-color-scheme="slate"] { + --md-hue: 190; + --md-accent-fg-color: #90c820; +} + +.md-header { + background: url(/static/banner.png) repeat-x; + background-color: var(--md-primary-fg-color); + background-size: 605px 75px; +} + +nav.md-tabs { + background: url(/static/banner-dark.png) repeat-x; + background-color: transparent; + background-size: 605px 75px; +} + +[data-md-component="palette"] { + display: none; +} + +/* version changed */ +:root { + /* Icon for "version-added" admonition: Material Design Icons "plus-box-outline" */ + --md-admonition-icon--version-added: url('data:image/svg+xml;charset=utf-8,'); + /* Icon for "version-changed" admonition: Material Design Icons "delta" */ + --md-admonition-icon--version-changed: url('data:image/svg+xml;charset=utf-8,'); + /* Icon for "version-removed" admonition: Material Design Icons "minus-circle-outline" */ + --md-admonition-icon--version-removed: url('data:image/svg+xml;charset=utf-8,'); +} + +.md-typeset .admonition.version-added, +.md-typeset .admonition.version-changed, +.md-typeset .admonition.version-removed { + border-radius: 3px; +} + +.md-typeset .admonition.version-added p.admonition-title, +.md-typeset .admonition.version-changed p.admonition-title, +.md-typeset .admonition.version-removed p.admonition-title { + font-weight: normal; +} + +/* "version-added" admonition in green */ +.md-typeset .admonition.version-added, +.md-typeset details.version-added { + border-color: rgb(11, 129, 38); +} + +.md-typeset .version-added>.admonition-title, +.md-typeset .version-added>summary { + background-color: rgba(4, 91, 40, 0.1); +} + +.md-typeset .version-added>.admonition-title::before, +.md-typeset .version-added>summary::before { + background-color: rgb(0, 200, 83); + -webkit-mask-image: var(--md-admonition-icon--version-added); + mask-image: var(--md-admonition-icon--version-added); +} + +/* "version-changed" admonition in orange */ +.md-typeset .admonition.version-changed, +.md-typeset details.version-changed { + border-color: rgb(255, 145, 0); +} + +.md-typeset .version-changed>.admonition-title, +.md-typeset .version-changed>summary { + background-color: rgba(255, 145, 0, .1); +} + +.md-typeset .version-changed>.admonition-title::before, +.md-typeset .version-changed>summary::before { + background-color: rgb(255, 145, 0); + -webkit-mask-image: var(--md-admonition-icon--version-changed); + mask-image: var(--md-admonition-icon--version-changed); +} + +/* "version-removed" admonition in red */ +.md-typeset .admonition.version-removed, +.md-typeset details.version-removed { + border-color: rgb(255, 82, 82); +} + +.md-typeset .version-removed>.admonition-title, +.md-typeset .version-removed>summary { + background-color: rgba(255, 82, 82, .1); +} + +.md-typeset .version-removed>.admonition-title::before, +.md-typeset .version-removed>summary::before { + background-color: rgb(255, 82, 82); + -webkit-mask-image: var(--md-admonition-icon--version-removed); + mask-image: var(--md-admonition-icon--version-removed); +} \ No newline at end of file diff --git a/static/favicon.svg b/static/favicon.svg new file mode 100644 index 0000000000..54cf6c428f --- /dev/null +++ b/static/favicon.svg @@ -0,0 +1,14 @@ + + + + + + + diff --git a/static/logo.svg b/static/logo.svg new file mode 100644 index 0000000000..e5f9906c95 --- /dev/null +++ b/static/logo.svg @@ -0,0 +1 @@ + \ No newline at end of file